Clojureのsend関数とsend-off関数。機能は全く同じのこの二つの関数の違いを確認する。
APIドキュメント
send
Usage: (send a f & args)
Dispatch an action to an agent. Returns the agent immediately.
Subsequently, in a thread from a thread pool, the state of the agent
will be set to the value of:
send-off
Usage: (send-off a f & args)
Dispatch a potentially blocking action to an agent. Returns the
agent immediately. Subsequently, in a separate thread, the state of
the agent will be set to the value of:
ブロッキングされる可能性がある処理は send-off を使えとの事。
具体的に何が違うのかソースを読んでみる。
ソースコード
core/send
(defn send
"Dispatch an action to an agent. Returns the agent immediately.
Subsequently, in a thread from a thread pool, the state of the agent
will be set to the value of:
(apply action-fn state-of-agent args)"
{:added "1.0"
:static true}
[^clojure.lang.Agent a f & args]
(apply send-via clojure.lang.Agent/pooledExecutor a f args))
core/send-off
(defn send-off
"Dispatch a potentially blocking action to an agent. Returns the
agent immediately. Subsequently, in a separate thread, the state of
the agent will be set to the value of:
(apply action-fn state-of-agent args)"
{:added "1.0"
:static true}
[^clojure.lang.Agent a f & args]
(apply send-via clojure.lang.Agent/soloExecutor a f args))
両関数ともに send-viaのラッパーで 違いは利用するExecutorServiceのみ。
send
は clojure.lang.Agent/pooledExecutor を、send-off
は clojure.lang.Agent/soloExecutor をデフォルトで利用している。
そしてデフォルトは
set-agent-send-executor!
set-agent-send-off-executor!で変更する事ができる。
clojure.lang.Agent/pooledExecutor
volatile public static ExecutorService pooledExecutor =
Executors.newFixedThreadPool(2 + Runtime.getRuntime().availableProcessors(),
createThreadFactory("clojure-agent-send-pool-%d", sendThreadPoolCounter));
send
が利用する pooledExecutor はプロセッサ数 + 2の固定のExecutorServiceを利用する。
CPU数に準じる固定数であるため、CPUバウンドな処理に向いている。
clojure.lang.Agent/soloExecutor
volatile public static ExecutorService soloExecutor = Executors.newCachedThreadPool(
createThreadFactory("clojure-agent-send-off-pool-%d", sendOffThreadPoolCounter));
一方 send-off
が利用する soloExecutor は可変のExecutorServiceを利用する。
可変(最大Integer.MAX_VALUE)であるため必要な分だけプールを広げてスレッドを起こすことができるためIOバウンドな処理に向いている。
また処理後の空きスレッドは60秒以内であれば再利用され60秒以上経つと破棄されてプールは縮小する。
まとめ
send
,send-off
の違いは利用するExecutorService。- ブロッキングする処理は
send-off
を利用する。 send-via
を関数を利用すると任意のExecutorServiceを利用することができる。send
が利用するExecutorServiceはset-agent-send-executor!
で変更可能。send-off
が利用するExecutorServiceはset-agent-send-off-executor!
で変更可能。