2017-04-10 2 views
1

Ich arbeite derzeit durch den allgegenwärtigen Prozess Ring in Elixier. Der Ring ist verbunden, aber in der folgenden Art und Weise:Link Asymmetrie im Prozess Ring

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

Ich habe eine Asymmetrie in den Links hier bemerkt - sollte #PID<0.120.0> haben die Zuordnung "links" => [#PID<0.121.0>,#PID<0.122.0>] anstatt nur "links" => [#PID<0.121.0>]?

Der Code ist wie folgt:

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 
+1

Können Sie einen [MCVE] (https://stackoverflow.com/help/mcve) posten? Wenn Sie die Links von 'Process.info (pid,: links) 'bekommen, rufen Sie sie möglicherweise zu früh auf. Die Links sollten symmetrisch sein, wenn der Prozess mit "Process.link/1" verknüpft wurde. – Dogbert

+0

@Dogbert sicher, aktualisiert. Ich verwende eine Verzögerung von einer Millisekunde. – category

+2

Ich denke, Sie müssen dies ändern, um 'Process.info (_,: links) 'zu sammeln, nachdem alle' Process.link/1'-Aufrufe getätigt wurden. – Dogbert

Antwort

2

Dies ist, weil Sie die Prozesse zur gleichen Zeit sind die Verknüpfung als :links zu sammeln, aber einige Links für diesen Prozess sind erstellt werden, nachdem Sie seine sammeln Links.

Zum Beispiel, wenn Sie einen Prozess a spawnen und dann seine Links sammeln, wird es eine leere Liste sein.

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

Wenn Sie b jetzt und verknüpfen es mit a laichen, wird b[a] in seiner Verbindungen haben und a wird [b] haben.

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

So müssen Sie die Links für jeden Prozess sammeln, nachdem alle die Verknüpfung abgeschlossen ist, wenn Sie die Endglieder für jeden Prozess wollen.

+0

Ich habe symmetrische Links gemeldet, indem ich die Links mit 'Process.info (_,: links) 'überprüft habe, nachdem die Funktion' link_processes/2' in der' create_ring_of_linked_processes/1'-Funktion ausgeführt wurde - aber das glaube ich nicht Dies garantiert, dass die "Verknüpfung ist abgeschlossen" - gibt es eine Möglichkeit, dies in Elixier zu wissen? Obwohl "send (pid, {: link, _})" ausgeführt wird, muss der "loop/0" -Prozess immer noch die Nachricht in einer unbekannten Zeitmenge empfangen und verarbeiten. – category

+1

Sie haben Recht, es ist nicht garantiert. Die übliche Vorgehensweise besteht darin, dass der Empfänger nach dem Abschluss der Verbindung eine weitere Nachricht an den Anrufer zurücksendet. Der Anrufer muss auf die Nachricht warten, bevor er fortfährt. 'GenServer.call' ist eine robuste Implementierung von etwas, das dem, was ich gerade beschrieben habe, sehr ähnlich ist; Vielleicht möchten Sie Ihren Prozess in einen GenServer verwandeln, wenn Sie dies in einer realen Anwendung verwenden möchten. – Dogbert

+0

Großartig, danke, werde tun - Markierung als Antwort, da es nur das Beispiel war, das keine Link-Reporting-Symmetrie garantiert hatte. – category