Process 过程环中的链路不对称

Process 过程环中的链路不对称,process,elixir,otp,symmetry,Process,Elixir,Otp,Symmetry,我目前正在使用elixir中无处不在的流程环。 环是链接的,但采用以下方式: iex(1)> Ring.Worker.create_ring_of_linked_processes(3) Ring.Worker.create_ring_of_linked_processes(3) [%{"links" => [#PID<0.121.0>, #PID<0.120.0>], "pid" => #PID<0.122.0>}, %{"links"

我目前正在使用elixir中无处不在的流程环。 环是链接的,但采用以下方式:

iex(1)> Ring.Worker.create_ring_of_linked_processes(3)
Ring.Worker.create_ring_of_linked_processes(3)
[%{"links" => [#PID<0.121.0>, #PID<0.120.0>], "pid" => #PID<0.122.0>},
 %{"links" => [#PID<0.120.0>, #PID<0.122.0>], "pid" => #PID<0.121.0>},
 %{"links" => [#PID<0.121.0>], "pid" => #PID<0.120.0>}]
iex(1)>Ring.Worker.创建链接进程的环(3)
创建链接进程的环(3)
[%{“links”=>[#PID,#PID],“PID”=>#PID},
%{“links”=>[#PID,#PID],“PID”=>#PID},
%{“links”=>[#PID],“PID”=>#PID}]
我注意到这里的链接有一个不对称性-
#PID
应该有映射
“links”=>[#PID,#PID]
而不仅仅是
“links”=>[#PID]

代码如下:

  def loop() do
    receive do
      {:link, pid} when is_pid(pid) ->
        Process.link(pid)
        loop()
    end
  end

  def create_ring_of_linked_processes(num_of_processes) do
    num_of_processes
    |> create_processes
    |> link_processes([])
  end


  def link_processes([pid1, pid2 | rest], linked_processes) do
    send(pid1, {:link, pid2})
    :timer.sleep(1)
    {:links, links} = Process.info(pid1, :links)
    link_processes(
      [pid2 | rest], [%{"pid" => pid1, "links" => links} | linked_processes]
    )
  end

  def link_processes([pid | []], linked_processes) do
    %{"pid" => first_pid, "links" => _} = List.last(linked_processes)
    send(pid, {:link, first_pid})
    :timer.sleep(1)
    {:links, links} = Process.info(pid, :links)
    [%{"pid" => pid, "links" => links} | linked_processes]
  end

  @spec create_processes(integer) :: [pid]
  def create_processes(num_of_processes) do
    for _ <- 1..num_of_processes, do: spawn(__MODULE__, :loop, [])
  end
def loop()do
接收do
{:link,pid}什么时候是_-pid(pid)->
进程链接(pid)
循环()
结束
结束
def创建链接进程的数量(进程的数量)do
进程数
|>创建流程
|>链接进程([]))
结束
def链接_进程([pid1,pid2 | rest],链接_进程)do
发送(pid1,{:链接,pid2})
:计时器。睡眠(1)
{:links,links}=Process.info(pid1,:links)
链接进程(
[pid2 | rest],%{“pid”=>pid1,“links”=>links}链接的|进程]
)
结束
def link_进程([pid |[]),linked_进程)do
%{“pid”=>first\u pid,“links”=>\u}=List.last(链接的\u进程)
发送(pid,{:链接,第一个\ pid})
:计时器。睡眠(1)
{:links,links}=Process.info(pid,:links)
[%{“pid”=>pid,“links”=>links}|链接的_进程]
结束
@规范创建_进程(整数):[pid]
def创建_进程(_进程的数量)do

对于{up>,这是因为您在收集流程的
:链接的同时链接了流程,但该流程的某些链接是在收集其链接后创建的

例如,如果生成一个进程
a
,然后收集它的链接,它将是一个空列表

iex(1)> a = spawn(fn -> :timer.sleep(:infinity) end)
#PID<0.82.0>
iex(2)> Process.info(a, :links)
{:links, []}

因此,如果您想要每个流程的最终链接,您需要在所有链接完成后收集每个流程的链接。

您可以发布一个链接吗?如果您从
Process.info(pid,:links)
获取链接,那么您可能调用它太早了。如果使用
process.link/1
@Dogbert-sure,updated链接进程,则链接应对称。我使用了一毫秒的延迟。我想在所有的
Process.link/1
调用完成后,您需要修改此设置以收集
Process.info(,:links)
。@Dogbert产生对称性,谢谢!请您将其作为一个答案提交,并说明为什么这样做有效,而上述内容无效?通过使用
Process.info(,:links)检查链接,我得到了对称的链接以进行报告
create\u ring\u of \u linked\u processs/1
函数中执行
link\u processs/2
函数后-但我不认为这保证了“链接是完整的”-在elixir中有什么方法知道这一点吗?即使执行了
send(pid,{:link,{})
loop/0
进程仍然需要在未知的时间内接收和处理消息。你是对的,这不是保证。通常的做法是让接收者在链接完成后向调用者发送另一条消息。呼叫方需要等待消息到达后才能继续
GenServer.call
是一个健壮的实现,与我刚才描述的非常相似;如果您打算在实际应用程序中使用它,您可能希望将您的流程转换为
GenServer
。很好,谢谢,可以-标记为答案,因为这只是一个没有保证链接报告对称性的示例。
iex(3)> b = spawn(fn -> Process.link(a); :timer.sleep(:infinity) end)
#PID<0.85.0>
iex(4)> Process.info(b, :links)
{:links, [#PID<0.82.0>]}
iex(5)> Process.info(a, :links)
{:links, [#PID<0.85.0>]}