ほぼ公式ドキュメントの意訳になってるので基本的には原文参照を推奨
Spawn/send/receiveでも可能だが、これらの処理をラップしたものが、おそらくTaskの位置づけとなる。
Supervisorを使わない方法(①)
Supervisorを使うなら、
または
## (1)非同期用に並列実行プロセスをcallして処理を渡す
task = Task.async(fn -> do_some_work() end)
## ...他の処理をおこなう
res = do_some_other_work()
## (2)並列実行プロセスから結果を貰う
res + Task.await(task)
async
をする際は必ずawait
するlink
関係
link
関係にしたくなければ、Task.start/1
やTask.Supervisor
などを利用するように。## Taskをuse
defmodule MyTask do
use Task
def start_link(arg) do
Task.start_link(__MODULE__, :run, [arg])
end
def run(arg) do
# ...
end
end
## wakeup
Supervisor.start_link([MyTask])
Task ModuleをuseしたModuleを作成して、Supervisorで起動することで、childにいるTaskとTaskが呼び出す関数を実行する方法
①との違い
(1) お手軽に書く
## (i)Supervisor起動
{:ok, pid} = Task.Supervisor.start_link()
## (ii) Task実行
task = Task.Supervisor.async(pid, fn ->
# Do something
end)
## (iii)Task実行結果取得
Task.await(task)
(2)厳格に書く
## (i) <MyApp.TaskSupervisor>などの、Task.Supervisorをuseする独自Moduleを作成
## (ii)起動定義
Supervisor.start_link([
{Task.Supervisor, name: MyApp.TaskSupervisor}
])
## (iii)起動
Task.Supervisor.start_child(MyApp.TaskSupervisor, fn ->
# ...Do something...
end)
## (iv)Task実行および実行結果取得
Task.Supervisor.async(MyApp.TaskSupervisor, fn ->
# Do something
end) |> Task.await()
Nodeを跨いだ動的なTaskの生成が可能
返り値を必要とする並列処理を書く際に自分で実装する場合はspawn/send/receiveを駆使して実装しないといけない。汎用的な並列処理結果の受け取り可能なTask
モジュールのおかげでそのあたりの実装が不要
使い分け
返り値を必要とする 並列処理を行いたいは Task.async/1
/Task.await/1
返り値を必要としない並列処理を行いたいは Task.start/1
(内部的にspawnを呼んでいるだけなので、spawnでも良いかも?優位点がわからない。オーバヘッドかかるだけなら、spawnを使うが)