7

良い一日、

gen_serverはいくつかの長期的な状態更新タスクを定期的に実行するプロセス を持っていますhandle_info

handle_info(trigger, State) ->
    NewState = some_long_running_task(),
    erlang:send_after(?LOOP_TIME, self(), trigger),
    {noreply, NewState}.

しかし、そのようなタスクが実行されると、サーバー全体が応答しなくなり、それを呼び出すとサーバー全体がクラッシュします。

my_gen_server:status().
** exception exit: {timeout,{gen_server,call,[my_gen_server,status]}}
     in function  gen_server:call/2

gen_serverのブロックを回避するにはどうすればよいですか?そして、いつでも1回呼び出すとmy_gen_server:status()、結果は次のようになります。 {ok, task_active}

4

2 に答える 2

13

長時間実行されるタスクを別のプロセスで実行します。このプロセスにタスクの進行状況をgen_serverに通知させるか(つまり、タスクの進行状況を追跡できる場合)、プロセスにタスクを完了するか失敗させますが、少なくともgen_serverにタスクの結果を通知します。

gen_serverをこの長時間実行タスクを実行するプロセスにリンクさせ、gen_serverにPIDまたは登録名を知らせて、終了シグナルの場合に、その重要なプロセスの停止を残りから分離できるようにします。

handle_info(trigger、State)->
    Pid = spawn_link(?MODULE、some_long_running_task、[State])、
    NewState = save_pid(Pid、State)、
    {noreply、NewState};
handle_info({'EXIT'、SomePid、_}、State)->
    case lookup_pid(State)== SomePid of
        false->%%他のプロセス
            {noreply、State};
        true->
            %%私たちのプロセスは死にました
            %% さて何をしようか ?
            %%別のものをスポーンしますか?
            %%それがあなたの決断です
            ...。
            ...。
            {noreply、State}
    終わり;
handle_info({finished、TaskResult}、State)->
    .....%%更新状態など
    erlang:send_after(?LOOP_TIME、self()、trigger)、
    {noreply、NewState}。

some_long_running_task(ServerState)->
    ....仕事する
    ....結果を返す
于 2012-01-16T12:14:26.293 に答える
5

この呼び出しはクラッシュにはつながりませが、キャッチできる例外につながるだけです。

status() ->
  try gen_server:call(my_gen_server, status)
  catch
    exit:{timeout,_} -> {ok, task_active}
  end.

ただし、呼び出しはサーバーのキューに残り、現在のメッセージの処理が終了した後、応答メッセージを送信します。{ServerRef, Reply}これは呼び出しプロセスによって破棄される必要があります。

Erlangでプロセスのブロックを回避する唯一の方法は(かどうかにgen_serverかかわらず)、Erlangでブロックタスクを実行しないことです。したがって、別の方法として、サーバーとのみ通信する別のプロセスで長いタスクを実行することもできます。これにより、サーバーがブロックされていることを誰も気にしません。

于 2012-01-16T11:47:47.970 に答える