Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/solr/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Elixir 为什么是随机顺序_Elixir - Fatal编程技术网

Elixir 为什么是随机顺序

Elixir 为什么是随机顺序,elixir,Elixir,我有下面的模块,模拟平行地图 defmodule Parallel do def pmap(collection, fun) do me = self collection |> Enum.map(fn (elem) -> spawn_link fn -> send(me, { self, fun.(elem) }) end end) |> Enum.map(

我有下面的模块,模拟平行地图

defmodule Parallel do

  def pmap(collection, fun) do
    me = self

    collection
        |> Enum.map(fn (elem) ->
                spawn_link fn -> send(me, { self, fun.(elem) }) end
             end)
        |> Enum.map(fn (pid) ->
                receive do { ^pid, result } ->
                    result
                end
        end)
  end
end
我编译、运行并获得预期结果:

iex(5)> Parallel.pmap 1..1000, &(&1 * &1)
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144, 169, 196, 225, 256 ...]
当我从
receive do{pid,result}->
中删除pin print操作符时,我将不再按正确的顺序获得列表:

[1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144, 169, 196, 256, 225, 289, 361...]

为什么pin运算符会影响订单

当您映射元素集合并为集合中的每个元素生成一个新进程时,您将返回一个PID列表:这些PID与您映射的集合的顺序相同,即。,给定
elem
的pid在pid列表中的位置与原始集合中的
elem
相同。这就是映射的工作原理,您可以对列表的每个元素应用一个操作,并获取这些操作的结果列表

现在,您可以映射PID列表。当您在
^pid
上进行匹配时,代码将被阻止,直到您要映射的当前
pid
的消息到达当前进程。但是,
{^pid,result}
消息可能不是当前进程消息队列中的唯一消息或第一个消息:因为所有生成的进程现在都并行运行,所以它们不会按照生成的顺序发送结果。这意味着,当您在
{^pid,result}
上接收并匹配时,消息队列可以在匹配
{^pid,result}
的消息之前有其他消息(
{pid\u 1,result\u 1}
{pid\u 2,result\u 2}
)。由于Erlang中接收进程的工作方式,如果这些消息与
receive
中的模式不匹配,则将跳过这些消息,直到其中一个匹配为止(或者我们一直等待新的匹配消息)

当您在
{pid,result}
上进行匹配时,您的意思是任何两个元素元组都可以:在这种情况下,
pid
很可能不是您当前映射的
pid
,原因与我上面提到的完全相同(派生的进程将以不可预测的顺序返回结果)

更直观的表示:假设在派生进程开始运行后,当前进程中有此消息队列(我们将调用派生进程
pid1
pid2
,等等):

假设您当前正在映射
pid1
(即,在传递给
Enum.map/2
的函数中,
pid
pid1

当您执行
接收do{^pid,res}->…
(使用
pid==pid1
)时,第一条消息将不匹配;因此,下一条消息将与此消息匹配
{pid3,res3}
将被放回消息队列,并且
接收
将使用
{pid1,res1}
执行。消息队列如下所示:

# The one on top is the first in the message queue:
{pid3, res3}
{pid4, res4}
{pid5, res5}
{pid2, res2}

回到原始队列:现在,如果您在
{pid,res}
上匹配(没有
^
pin操作符),任何两个元素元组都将匹配;具体来说,
{pid3,res3}
将匹配,
接收
块将与之一起执行(即使我们映射的
pid
pid1
)。这意味着在结果列表中,第三个元素的结果(为其生成了
pid3
)将取代第一个元素的结果:随机顺序

当您映射元素集合并为集合中的每个元素生成一个新进程时,您将返回一个PID列表:这些PID与您映射的集合的顺序相同,即。,给定
elem
的pid在pid列表中的位置与原始集合中的
elem
相同。这就是映射的工作原理,您可以对列表的每个元素应用一个操作,并获取这些操作的结果列表

现在,您可以映射PID列表。当您在
^pid
上进行匹配时,代码将被阻止,直到您要映射的当前
pid
的消息到达当前进程。但是,
{^pid,result}
消息可能不是当前进程消息队列中的唯一消息或第一个消息:因为所有生成的进程现在都并行运行,所以它们不会按照生成的顺序发送结果。这意味着,当您在
{^pid,result}
上接收并匹配时,消息队列可以在匹配
{^pid,result}
的消息之前有其他消息(
{pid\u 1,result\u 1}
{pid\u 2,result\u 2}
)。由于Erlang中接收进程的工作方式,如果这些消息与
receive
中的模式不匹配,则将跳过这些消息,直到其中一个匹配为止(或者我们一直等待新的匹配消息)

当您在
{pid,result}
上进行匹配时,您的意思是任何两个元素元组都可以:在这种情况下,
pid
很可能不是您当前映射的
pid
,原因与我上面提到的完全相同(派生的进程将以不可预测的顺序返回结果)

更直观的表示:假设在派生进程开始运行后,当前进程中有此消息队列(我们将调用派生进程
pid1
pid2
,等等):

假设您当前正在映射
pid1
(即,在传递给
Enum.map/2
的函数中,
pid
pid1

当您执行
接收do{^pid,res}->…
(使用
pid==pid1
)时,第一条消息将不匹配;因此,下一条消息将与此消息匹配
{pid3,res3}
将被放回消息队列,并且
接收
将使用
{pid1,res1}
执行。消息队列如下所示:

# The one on top is the first in the message queue:
{pid3, res3}
{pid4, res4}
{pid5, res5}
{pid2, res2}
回到原始队列:现在,如果您在
{pid,res}
上匹配(没有
^
pin操作符),任何两个元素元组都将匹配;具体来说,
{p
{pid3, 9}
{pid2, 4}
{pid1, 1}