私はバックグラウンドで連続して実行されている単純なオシレーターをモデル化しようとしています(サイン関数を統合しています)。しかし、ある時点では、内部の状態に保たれたその値(電圧と時間)を要求できるようにしたいと考えています。後者の点では、オシレータのプールを監視し、スーパーバイザが電圧/値、および他の一握りの操作を平均するためです。エリクサー/ OTP連続バックグラウンドジョブと状態の参照
私はこのアプローチに達しました。これはget_state
サーバの実装を終了する前にrun()
を実行する必要があるため、私は100%満足していません。 handle_call({:get_state, pid}.....)
。
私は試してみることができる他のアプローチはありますか?基礎となるProcess
に "カチカチ" を委任
defmodule World.Cell do
use GenServer
@timedelay 2000
# API #
#######
def start_link do
GenServer.start_link(__MODULE__, [], [name: {:global, __MODULE__}])
end
def run do
GenServer.cast({:global, __MODULE__}, :run)
end
def get_state(pid) do
GenServer.call(pid, {:get_state, pid})
end
# Callbacks #
#############
def init([]) do
:random.seed(:os.timestamp)
time = :random.uniform
voltage = :math.sin(2 * :math.pi + time)
state = %{time: time, voltage: voltage }
{:ok, state, @timedelay}
end
def handle_cast(:run, state) do
new_time = state.time + :random.uniform/12
new_voltage = :math.sin(2 * :math.pi + new_time)
new_state = %{time: new_time, voltage: new_voltage }
IO.puts "VALUES #{inspect self()} t/v #{new_time}/#{new_voltage}"
{:noreply, new_state, @timedelay}
end
def handle_info(:timeout, state) do
run() # <--------------------- ALWAYS HAVING TO RUN IT
{:noreply, state, @timedelay}
end
def handle_call({:get_state, pid}, _from, state) do
IO.puts "getting state"
run() # <--------------------- RUN UNLESS IT STOPS after response
{:reply, state, state}
end
end
アップデート1
アプローチ、私はElixirForumで受信replyのおかげ。
defmodule World.Cell do
use GenServer
@timedelay 2000
def start_link do
GenServer.start_link(__MODULE__, [], [name: {:global, __MODULE__}])
end
def get_state(pid) do
GenServer.call(pid, {:get_state, pid})
end
def init([]) do
:random.seed(:os.timestamp)
time = :random.uniform
voltage = :math.sin(2 * :math.pi + time)
timer_ref = Process.send_after(self(), :tick, @timedelay)
state = %{time: time, voltage: voltage, timer: timer_ref}
{:ok, state}
end
def handle_info(:tick, state) do
new_state = run(state)
timer_ref = Process.send_after(self(), :tick, @timedelay)
{:noreply, %{new_state | timer: timer_ref}}
end
def handle_call({:get_state, pid}, _from, state) do
IO.puts "getting state"
return = Map.take(state, [:time, :voltage])
{:reply, return, state}
end
defp run(state) do
new_time = state.time + :random.uniform/12
new_voltage = :math.sin(2 * :math.pi + new_time)
new_state = %{state | time: new_time, voltage: new_voltage}
IO.puts "VALUES #{inspect self()} t/v #{new_time}/#{new_voltage}"
new_state
end
end
ありがとうございます!私は新しいアプローチで質問を更新しました。これは概念的にあなたのものに近いものです。私はあなたに質問したいと思います:1)あなたのアプローチでは、 "ticking"( '{:ping}')と "state retrieval"( '{state、caller}')の両方のロジックを同じ「ループ/受信」機能。 2つの異なるプロセスがあるとすれば、ロジックを(Update1のように)私の質問と区別する方が良いのではないでしょうか? 2)これは自律的に動作するオシレータのプールであり、理想的には監督されていることを考慮してください(したがって、ティッキングが失敗した場合などに再起動します)。 'Process'または' Task'を使う方が良いでしょうか? – lllllll
タスクは両方に応答する準備ができているので、同じ 'receive 'になければなりません。これを2つの異なる 'handle_call'実装として扱います。 'タスク'、 'プロセス'、 'ジェンサーバー'など、習慣や個人的な選択の問題があります。その答えは非常に偏っており、非常に意見に基づいています。 – mudasobwa