Enum.map如何与Task.await一起使用?

时间:2017-02-21 05:17:41

标签: asynchronous concurrency async-await elixir

Elixir Enum.map([Task.t], &Task.await)如何运作?

async_1 = Task.async(fn ->
  IO.inspect("done async 1") 
  1
end)

async_2 = Task.async(fn ->
  IO.inspect("done async 2")
  2
end)

results = Enum.map([async_1, async_2], fn(task) ->
  IO.inspect("starting new task")
  IO.inspect(task)
  Task.await(task) 
end)

IO.inspect(results)

从上面的代码中,我得到了IO日志:

"starting new task"
"done async 1"
"done async 2"
%Task{pid: #PID<0.51.0>, ref: #Reference<0.0.0.78>}
"starting new task"
%Task{pid: #PID<0.52.0>, ref: #Reference<0.0.0.79>}
[1, 2]
  1. 我希望第二个"starting new task"出现在"done async 2"之前。它是如何急切地执行所有异步任务的呢?
  2. doc开始,await将“等待任务回复并将其返回”。我认为这意味着它将暂停调用者进程,直到从Task进程发回完成消息。如果是这种情况,它应该在每个Task.await(Task.t)迭代中的map的每次调用中暂停,并且从不真正同时执行这些任务。日志证明我的假设是错误的。但哪里错了?
  3. 这是我的repl http://elixirplayground.com?gist=f1fa90eadc00441a360d8bc883d64529

2 个答案:

答案 0 :(得分:4)

Task.async不等到Task.await运行传递给它的函数;它立即开始运行。这里给任务的工作量非常小,所以当Enum.map有机会等待第二个任务时,它们都已经完成了它的执行。

答案 1 :(得分:0)

感谢@Dogbert的启示。我误解了Elixir中的Task.async

它使我感到困惑,因为在ES7和C#中,async只是一个关键字,表示该函数将返回PromiseAsyncableasync仅限于定义&#34; async_function&#34;。 await执行两项操作 - 执行并等待结果。即。

function async(action: fn): Promise
function await(async_action: Promise): ?Any { execute_and_wait(async_function) } 

在Elixir中,Task.async将在新进程中执行该函数,该进程类似于start_link。并且await仅等待执行过程返回结果。

不是说设计不合理。但是我更希望他们称之为async以外的东西,因为它打破了其他常用语言的惯例,因此更难以学习。