エンジニアのソフトウェア的愛情

または私は如何にして心配するのを止めてプログラムを・愛する・ようになったか

互いに依存しない同じ処理を複数実行するには Task.Supervisor.async_stream が便利だという覚書

複数のデータに対して、同じ処理を適用する場合、Task.Supervisor.async_stream を利用すると、個々の処理を並列で実行してくれます。CPU を存分に酷使してくれます。

defmodule Sample do
  require Integer

  @doc """
  Collatz conjecture

  see [Collatz conjecture - Wikipedia](https://en.wikipedia.org/wiki/Collatz_conjecture)
  """
  def collatz(n) when is_integer(n) and n > 0, do: collatz(n, [])
  def collatz(1, acc), do: [1 | acc] |> Enum.reverse() |> Enum.join(",")
  def collatz(n, acc) when Integer.is_odd(n), do: collatz(n * 3 + 1, [n | acc])
  def collatz(n, acc), do: collatz(div(n, 2), [n | acc])

  def run do
    # Task.Supervisor をスタートします
    Task.Supervisor.start_link(name: Task.SampleSupervisor)

    Task.SampleSupervisor
    |> Task.Supervisor.async_stream(1..10, Sample, :collatz, [], orderd: false, timeout: :infinity)
    |> Enum.map(&IO.inspect/1)
  end
end

Task.Supervisor.async_stream はストリームを生成するので、結果を得るには Enum.to_list/1 などを利用して要素を評価する必要があります。ここでは Enum.map/2 を使って個々の要素を IO.inspect/1 で出力しています。

実行。

 $ mix run -e 'Sample.run()'
{:ok, "1"}
{:ok, "2,1"}
{:ok, "3,10,5,16,8,4,2,1"}
{:ok, "4,2,1"}
{:ok, "5,16,8,4,2,1"}
{:ok, "6,3,10,5,16,8,4,2,1"}
{:ok, "7,22,11,34,17,52,26,13,40,20,10,5,16,8,4,2,1"}
{:ok, "8,4,2,1"}
{:ok, "9,28,14,7,22,11,34,17,52,26,13,40,20,10,5,16,8,4,2,1"}
{:ok, "10,5,16,8,4,2,1"}

個々の結果は、処理が成功した場合は :ok と処理結果のペアがタプルで返ります。