定期的なメッセージ送信

アーランに関する投稿ですが、他のすべての言語に適用されます。



たとえば、HTTP URLを介してファイルの存在を確認するなど、1秒間に1回何かを実行したいとします。 私たちはこのためのプロセスを開始しました、彼が十分に定期的に何かをすることが必要です。



erlangに興味がある3つの関数があります:timer:send_interval、timer:send_after、およびerlang:send_after。



まず、send_intervalを使用できない理由を説明します。







timer:send_intervalは、前のメッセージが処理されたかどうかを確認せずにメッセージを送信するという点で問題があります。 その結果、タスクの実行が停止し始めた場合、プロセスはこのタスクのみを処理します。 悪いケースでは、キュー内のメッセージの蓄積が始まり、メモリリークが発生し、プロセスの応答性が完全に失われます。



プロセスのmessage_queueで数百のチェックメッセージを繰り返し確認しました。



さらに、外部リソースの強姦が始まります:ハードドライブまたはリモートサーバー。 確かに、毎秒休憩する代わりに、それはまったくないかもしれません。



したがって、正しい手順は、タスク処理の最後にメッセージを自分に転送することです。



タイマー:send_afterとerlang:send_afterの間では、選択は明らかです:erlang:send_after。 タイマーモジュールはこれを非常に非最適に実行し、多くのタイマーが問題を引き起こし始めます。



erlangを使用しない唯一の理由:send_afterは数千のプロセスがあり、処理が困難なタイマーをシステムにロードせずにメッセージをグループ化できる場合ですが、これは非常にまれな状況です。



ただし、ここで間違いを犯すのは簡単です。



init([]) -> self() ! check, {ok, state}. handle_info(check, State) -> do_job(State), erlang:send_after(1000, self(), check), {noreply, State}.
      
      







他の誰かがプロセスにチェックメッセージを送信するとどうなりますか? 各チェックメッセージが保証されたリタイマーにつながるため、2番目のウェーブが生成されます。



その結果、20個のメッセージを送信する場合、各瞬間のプロセスには20個のタイマーがあり、その数は減りません。



正解は次のとおりです。

 init([]) -> Timer = erlang:send_after(1, self(), check), {ok, Timer}. handle_info(check, OldTimer) -> erlang:cancel_timer(OldTimer), do_task(), Timer = erlang:send_after(1000, self(), check), {noreply, Timer}.
      
      





タイマーを明示的に削除すると、1000件のメッセージを送信した場合、それらはすべて処理され、その後、プロセスはすぐに正常化され、メッセージ転送は1回だけになります。



All Articles