1

我目前正在研究 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>}]

我注意到这里的链接不对称 - 应该#PID<0.120.0>有映射"links" => [#PID<0.121.0>,#PID<0.122.0>]而不仅仅是"links" => [#PID<0.121.0>]

代码如下:

  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
4

1 回答 1

2

这是因为您在收集它的同时链接这些进程,但是在您收集它的链接之后:links正在为该进程创建一些链接。

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

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

如果您b现在生成并将其链接到a,b[a]在其链接a中具有[b].

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>]}

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

于 2017-04-13T12:19:35.950 回答