Current section
Files
Jump to
Current section
Files
lib/zigzag.ex
defmodule Zigzag do
@doc """
Applies `fun` to each item of `list` in parallel, running at most `limit`
processes at any given time.
## Examples
iex> Zigzag.each([1, 2, 3], 3, fn _ -> nil end)
:ok
"""
def each(list, limit, fun) do
each(list, limit, fun, make_ref(), 0)
end
defp each([], _limit, _fun, _ref, 0), do: :ok
defp each([h|t], limit, fun, ref, running) when running < limit do
me = self
spawn_link(fn ->
fun.(h)
send me, {ref, :cont}
end)
each(t, limit, fun, ref, running + 1)
end
defp each(list, limit, fun, ref, running) when is_list(list) do
receive do
{^ref, :cont} -> each(list, limit, fun, ref, running - 1)
end
end
@doc """
Applies `fun` to each item of `list` in parallel, returning the return values
of `fun` in a list in an unspecified order, running at most `limit` processes
at any given time.
## Examples
iex> Zigzag.unordered_map([1, 2, 3], 3, fn x -> x * 2 end) |> Enum.sort
[2, 4, 6]
"""
def unordered_map(list, limit, fun) do
unordered_map(list, limit, fun, make_ref(), 0, [])
end
defp unordered_map([], _limit, _fun, _ref, 0, acc), do: acc
defp unordered_map([h|t], limit, fun, ref, running, acc) when running < limit do
me = self
spawn_link(fn ->
send me, {ref, :cont, fun.(h)}
end)
unordered_map(t, limit, fun, ref, running + 1, acc)
end
defp unordered_map(list, limit, fun, ref, running, acc) when is_list(list) do
receive do
{^ref, :cont, x} -> unordered_map(list, limit, fun, ref, running - 1, [x | acc])
end
end
@doc """
Applies `fun` to each item of `list` in parallel, returning the return values
of `fun` in a list in the same order as `list`, running at most `limit`
processes at any given time.
## Examples
iex> Zigzag.map([1, 2, 3], 3, fn x -> x * 2 end)
[2, 4, 6]
"""
def map(list, limit, fun) do
map(list, limit, fun, make_ref(), 0, 0, [])
end
defp map([], _limit, _fun, _ref, 0, _started, acc) do
:lists.keysort(1, acc) |> Enum.map(fn {_i, x} -> x end)
end
defp map([h|t], limit, fun, ref, running, started, acc) when running < limit do
me = self
spawn_link(fn ->
send me, {ref, :cont, started, fun.(h)}
end)
map(t, limit, fun, ref, running + 1, started + 1, acc)
end
defp map(list, limit, fun, ref, running, started, acc) when is_list(list) do
receive do
{^ref, :cont, i, x} ->
map(list, limit, fun, ref, running - 1, started, [{i, x} | acc])
end
end
end