我目前通过网站exercism.io学习Elixir。 我遇到了问题" Sum Of Multiples"这是:
如果我们列出所有自然数字,但不包括20 3或5的倍数,我们得到3,5,6和9,10,12,15和18。 这些倍数的总和是78
我用这段代码解决了这个问题:
defmodule SumOfMultiples do
@doc """
Adds up all numbers from 1 to a given end number that are multiples of the factors provided.
"""
@spec to(non_neg_integer, [non_neg_integer]) :: non_neg_integer
def to(limit, factors) do
1..limit - 1
|> Enum.reduce([], fn(x,acc) ->
is_multiple? = factors
|> Enum.map(&(rem(x,&1) === 0))
|> Enum.any?
if is_multiple?, do: [x|acc], else: acc
end)
|> Enum.sum
end
end
但我最近在Elixir中发现了进程,所以我想用多进程解决问题:
defmodule SumOfMultiples do
@doc """
Adds up all numbers from 1 to a given end number that are multiples of the factors provided.
"""
@spec to(non_neg_integer, [non_neg_integer]) :: non_neg_integer
def to(limit, factors) do
me = self
1..limit - 1
|> Enum.map(fn(x) ->
spawn(SumOfMultiples, :is_multiple?, [x, factors, me])
end)
|> Enum.map(fn(_) ->
receive do
{true, n} -> n
{false, n} -> 0
end
end)
|> Enum.sum
end
def is_multiple?(n, factors, pid) do
flag = factors
|> Enum.map(&(rem(n,&1) === 0))
|> Enum.any?
send pid, {flag, n}
end
end
我用并行映射来解决这个问题。是否有效但事情是它比单一过程版本低4倍。
如果有人能解释为什么会有这样的性能差异,那将是非常有用的,因为我已计划用多进程版本来解决剩余的exercism.io问题。
谢谢!
--------------------- update ---------------------
感谢您的回答!事实证明你是对的!谢谢你的解释!这是我的新实现:
defmodule SumOfMultiples do
@doc """
Adds up all numbers from 1 to a given end number that are multiples of the factors provided.
"""
@spec to(non_neg_integer, [non_neg_integer]) :: non_neg_integer
def to(limit, factors) do
me = self
1..limit - 1
|> Stream.chunk(200, 200, Stream.cycle([0]))
|> Enum.map(fn(x) ->
spawn(SumOfMultiples, :do_to, [x, factors, me])
end)
|> Enum.map(fn(_) ->
receive do
n -> n
end
end)
|> Enum.sum
end
def do_to(list, factors, pid) do
result = list
|> Enum.reduce([], fn(x,acc) ->
is_multiple? = factors
|> Enum.map(&(rem(x,&1) === 0))
|> Enum.any?
if is_multiple?, do: [x|acc], else: acc
end)
|> Enum.sum
send pid, result
end
end
最大似乎是200.现在我比单个进程快40%! YAY!
答案 0 :(得分:3)
问题在于你将工作分得太薄了。启动新流程的开销大于并行执行此操作的收益。一次进程(直到它将由VM重新安排)被给予2000次减少,这或多或少地对应于2000次函数调用。要看到并行化的真正好处,您应该尝试将该工作拆分为该大小的块,以便从并行化工作中获得最大收益。