以前学习的 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