以前學習的 Agent,GenSever以及GenEvent,都是用來管理狀態或者處理消息的。
可是在不少時候,咱們須要的是執行某個任務,這時若是使用 GenSever 或者 GenEvent,就會顯得比較笨重。多線程
這時,咱們就可使用 Task 模塊,使用 Task 模塊時注意如下幾點:併發
task 最重要的特性是可以方便的將順序執行的代碼轉變爲併發執行的代碼。異步
defmodule TaskTest do def test_sync() do for n <- [1,2,3,4] do :timer.sleep(1000) IO.puts("it's #{n} #{TimeUtil.now}") end end def test_async() do for n <- [1,2,3,4] do Task.start_link(fn -> :timer.sleep(1000) IO.puts("it's #{n} #{TimeUtil.now}") end) end end defmodule TimeUtil do def now() do {{y,m,d}, {h,mm,s}} = :calendar.local_time "#{y}/#{m}/#{d} #{h}:#{mm}:#{s}" end end IO.puts "execute sync" TaskTest.test_sync IO.puts "===============================" IO.puts "execute async" TaskTest.test_async
執行結果以下:async
iex(1)> r(TaskTest) execute sync it's 1 2016/5/31 13:53:2 it's 2 2016/5/31 13:53:3 it's 3 2016/5/31 13:53:4 it's 4 2016/5/31 13:53:5 =============================== execute async it's 1 2016/5/31 13:53:6 it's 2 2016/5/31 13:53:6 it's 3 2016/5/31 13:53:6 it's 4 2016/5/31 13:53:6
defmodule TaskTest do def exec_task() do t = Task.async(fn -> IO.puts("start to do something at #{TimeUtil.now}") :timer.sleep(3000) end) t end def get_task_result(t) do Task.await(t, 5000) IO.puts("get something result at #{TimeUtil.now}") end end defmodule TimeUtil do def now() do {{y,m,d}, {h,mm,s}} = :calendar.local_time "#{y}/#{m}/#{d} #{h}:#{mm}:#{s}" end end t = TaskTest.exec_task # 異步執行 IO.inspect(TaskTest.get_task_result(t)) # 同步獲取執行結果
運行結果以下:學習
iex(1)> r(TaskTest) start to do something at 2016/5/31 14:24:48 get something result at 2016/5/31 14:24:51 :ok
注意 若是 get_task_result 中 Task.await 的超時時間設置的小於task的執行時間的話(好比await的時間由 5000 -> 2000),
那麼,會致使 get_task_result timeout的錯誤。線程
從上面的例子能夠看出,利用 Task 模塊,能夠很方便的實現併發和異步操做。
可是,在用 task 執行任務的時候,咱們發現,在併發和異步的環境中,若是某個 task 執行失敗的話,甚至會致使主進程也失敗。code
下一節的監督者機制,將介紹 elixir 如何利用 OTP平臺 完美解決上述併發和異步中的問題。blog