2016-01-27 110 views
0

我在GenServer测试以下模式GenServer(gen_server):处理数据

def handle_info({:tcp, _, data}, s) do 
    # IO.puts "\nrx: \n#{Base.encode16(data)}\n" 

    extra = _proc_data(<<s.extra::binary, data::binary>>) 

    :inet.setopts(s.socket, active: :once) 

    {:noreply, %{s | extra: extra}} 
    end 

有一个问题,当数据来自于快,我无法前:inet.setopts(s.socket, active: :once)版本更新状态新数据

必须{:noreply, %{s | extra: extra}}成为handle_info的最后一行,还是可以最后执行:inet.setopts(s.socket, active: :once)

有没有更好的方法来做到这一点?

+0

的':noreply'确实需要的最后一件事,因为它是函数的返回值。关于更新状态,它是否可以解决您的问题,以便从此功能获得另一个'GenServer'调用?我在理解确切的问题时遇到了一些麻烦,但是您可能会将此路径作为重构开始。 –

+0

@ChristianDiLorenzo问题出自以前调用'_proc_data'我可能有额外的字节,我需要在'GenServer状态'中保存,并在处理之前预先添加到任何新数据。在'handle_info'中最后调用'{:noreply,new_state}'的要求成为了一个问题,因为调用':inet.setopts(s.socket,active :::once)''会在我保存额外内容之前释放新数据上一步 –

+1

只要'_proc_data'不接收任何消息,您的代码就像写入的那样是正确的。 'setopts'调用释放的任何附加数据将被放置在消息队列中,'gen_server'将再次调用您的'handle_info'函数。效果与数据刚刚在返回'handle_info'之后到达相同。 – legoscia

回答

1

我曾经使用过的一种技术是将数据发送到另一个GenServer进行处理。这将允许当前进程更快地呼叫:inet.setopts(s.socket, active: :once)

def handle_info({:tcp, _, data}, s) do 
    # IO.puts "\nrx: \n#{Base.encode16(data)}\n" 

    GenServer.cast(s.processor, {:data, data}) 

    :inet.setopts(s.socket, active: :once) 

    {:noreply, s} 
end 

处理器:

defmodule DataProcessor do 
    use GenServer 

    def start_link(opts), do: GenServer.start_link(__MODULE__, [], opts) 

    def init(_), do: {:ok, %{}} 

    def handle_cast({:data, data}, state) do 
    extra = _proc_data(s.extra <> data)  
    {:noreply, %{state| extra: extra}} 
    end 

    defp _proc_data(data) do 
    ... 
    end 
end