Elixir Stream中的Task.async

时间:2015-09-15 14:53:46

标签: parallel-processing elixir

我想在一个大清单上做一个平行地图。代码看起来有点像这样:

big_list
|> Stream.map(&Task.async(Module, :do_something, [&1]))
|> Stream.map(&Task.await(&1))
|> Enum.filter filter_fun

但是我正在检查Stream实现,据我所知Stream.map组合了函数并将组合函数应用于流中的元素,这意味着序列是这样的:

  1. 采取第一个元素
  2. 创建异步任务
  3. 等待它完成
  4. 选择第二个......
  5. 在这种情况下,它不会并行执行。我是对的还是我错过了什么?

    如果我是对的,那么这段代码呢?

    Stream.map Task.async ...
    |> Enum.map Task.await ...
    

    这是否会并行运行?

3 个答案:

答案 0 :(得分:13)

第二个也没有做你想要的。您可以使用以下代码清楚地看到它:

defmodule Test do
  def test do
    [1,2,3]
    |> Stream.map(&Task.async(Test, :job, [&1]))
    |> Enum.map(&Task.await(&1))
  end

  def job(number) do
    :timer.sleep 1000
    IO.inspect(number)
  end
end

Test.test

你会看到一个数字,然后是1秒等待,另一个数字,依此类推。这里的关键是你想尽快创建任务,所以你不应该使用 懒惰Stream.map。而是在那时使用渴望的Enum.map

|> Enum.map(&Task.async(Test, :job, [&1]))
|> Enum.map(&Task.await(&1))

另一方面,您可以在等待时使用Stream.map,只要您稍后进行一些急切操作,就像filter一样。通过这种方式,等待将穿插您可能对结果进行的任何处理。

答案 1 :(得分:6)

Elixir 1.4提供了新的Task.async_stream/5函数,它将返回一个在可枚举项中的每个项目上同时运行给定函数的流。

还可以使用:max_concurrency:timeout选项参数指定最大工作人数和超时时间。

请注意,您不必等待此任务,因为该函数会返回一个流,因此您可以使用Enum.to_list/1或使用Stream.run/1

这将使您的示例同时运行:

big_list
|> Task.async_stream(Module, :do_something, [])
|> Enum.filter(filter_fun)

答案 2 :(得分:0)

您可以尝试Parallel Stream

"mailingAddress." + position + ".active"

UPD 或者更好地使用Flow