2016-01-27 147 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