簡體   English   中英

等待進程Erlang的回復

[英]Wait on the reply of a process Erlang

是否有可能在模塊module1的功能funct1中生成進程p,在模塊1的功能funct2中向p發送消息,並在funct2內部等待p的答復,而不必生成因此被認為是f2的f2。自()? 如果是這樣,實現等待部分的最佳方法是什么? 您可以查看下面的代碼以大致了解我要查找的內容。 提前致謝。

-module(module1)
...
funct1(...)
->  

 Pid = spawn(module2, function3, [[my_data]]),
 ...


funct2(...)
->
  ...
  Pid ! {self(), {data1, data2}},

  % wait here for the reply from Pid
  % do something here based on the reply.

答案

是。

真正的問題

您正在混淆三個概念:

  • 進程(誰是self()和什么是pid()
  • 功能
  • 模組

一個過程是有生命的東西。 進程具有其自己的內存空間。 這些過程就是打電話的過程 這是唯一真正重要的身份。 當您想到“在這種情況下誰是self() ”時,您實際上是在問“調用上下文是什么?” 如果我生成一個進程的兩個實例,它們可能會在其生命中的某個時刻調用相同的函數-但這些調用的上下文是完全不同的,因為進程具有自己的生命和自己的內存空間。 僅僅因為Victor和Victoria都在同一時間跳繩,並不會使他們成為同一個人。

人們對調用上下文最困惑的地方是編寫模塊接口函數時 為了簡單起見,大多數模塊都是以僅定義一個過程的方式編寫的。 沒有強制要求這樣做的規則,但是以這種方式編寫模塊時,很容易理解模塊的功能。 接口函數已導出,可供任何進程調用-它們在調用它們的進程的上下文中進行調用, 而不是在生成為“成為該模塊的實例”並運行其中定義的服務循環的進程的上下文中進行調用。

但是,沒有什么東西可以進程在該模塊中。 我可以編寫一對模塊,一個模塊定義獅子的AI,另一個模塊定義鯊魚的AI,並在其執行過程中使進程本質上切換身份-但這總是一個非常糟糕的主意(因為它變得令人困惑)。

功能就是功能。 僅此而已。 模塊由功能組成。 沒什么可說的了。

如何等待消息

我們使用receive構造等待消息。 它與收到的消息匹配(將始終是Erlang術語),並根據消息的形狀和/或內容選擇要執行的操作。

仔細閱讀以下內容:

1> Talker =
1>   fun T() ->
1>     receive
1>       {tell, Pid, Message} ->
1>         ok = io:format("~p: sending ~p message ~p~n", [self(), Pid, Message]),
1>         Pid ! {message, Message, self()},
1>         T();
1>       {message, Message, From} ->
1>         ok = io:format("~p: from ~p received message ~p~n", [self(), From, Message]),
1>         T();
1>       exit ->
1>         exit(normal)
1>     end
1>   end.
#Fun<erl_eval.44.87737649>
2> {Pid1, Ref1} = spawn_monitor(Talker).
{<0.64.0>,#Ref<0.1042362935.2208301058.9128>}
3> {Pid2, Ref2} = spawn_monitor(Talker).
{<0.69.0>,#Ref<0.1042362935.2208301058.9139>}
4> Pid1 ! {tell, Pid2, "A CAPITALIZED MESSAGE! RAAAR!"}.
<0.64.0>: sending <0.69.0> message "A CAPITALIZED MESSAGE! RAAAR!"
{tell,<0.69.0>,"A CAPITALIZED MESSAGE! RAAAR!"}
<0.69.0>: from <0.64.0> received message "A CAPITALIZED MESSAGE! RAAAR!"
5> Pid2 ! {tell, Pid1, "a lower cased message..."}.
<0.69.0>: sending <0.64.0> message "a lower cased message..."
{tell,<0.64.0>,"a lower cased message..."}
<0.64.0>: from <0.69.0> received message "a lower cased message..."
6> Pid1 ! {tell, Pid1, "Sending myself a message!"}.
<0.64.0>: sending <0.64.0> message "Sending myself a message!"
{tell,<0.64.0>,"Sending myself a message!"}
<0.64.0>: from <0.64.0> received message "Sending myself a message!"
7> Pid1 ! {message, "A direct message from the shell", self()}.
<0.64.0>: from <0.67.0> received message "A direct message from the shell"
{message,"A direct message from the shell",<0.67.0>}

一個獨立的例子

現在考慮一下乒乓球服務的手稿。 注意,這里只是一種內部定義健談的,它知道如何處理targetpingpong消息。

#! /usr/bin/env escript

-mode(compile).

main([CountString]) ->
    Count = list_to_integer(CountString),
    ok = io:format("~p: Starting pingpong script. Will iterate ~p times.~n", [self(), Count]),
    P1 = spawn_link(fun talker/0),
    P2 = spawn_link(fun talker/0),
    pingpong(Count, P1, P2).


pingpong(Count, P1, P2) when Count > 0 ->
    P1 ! {target, P2},
    P2 ! {target, P1},
    pingpong(Count - 1, P1, P2);
pingpong(_, P1, P2) ->
    _ = erlang:send_after(1000, P1, {exit, self()}),
    _ = erlang:send_after(1000, P2, {exit, self()}),
    wait_for_exit([P1, P2]).


wait_for_exit([]) ->
    ok = io:format("~p: All done, Returing.~n", [self()]),
    halt(0);
wait_for_exit(Pids) ->
    receive
        {exiting, Pid} ->
            ok = io:format("~p: ~p is done.~n", [self(), Pid]),
            NewPids = lists:delete(Pid, Pids),
            wait_for_exit(NewPids)
    end.


talker() ->
    receive
        {target, Pid} ->
            ok = io:format("~p: Sending ping to ~p~n", [self(), Pid]),
            Pid ! {ping, self()},
            talker();
        {ping, From} ->
            ok = io:format("~p: Received ping from ~p. Replying with pong.~n", [self(), From]),
            From ! pong,
            talker();
        pong ->
            ok = io:format("~p: Received pong.~n", [self()]),
            talker();
        {exit, From} ->
            ok = io:format("~p: Received exit message from ~p. Retiring.~n", [self(), From]),
            From ! {exiting, self()}
    end.

那里有一些細節,例如使用erlang:send_after/3 ,是因為消息發送是如此之快 ,以至於超過了對io:format/2的調用速度,從而減慢了實際的talker進程並導致了奇怪的情況。退出消息(通常)在兩個講話者之間的乒乓球和乒乓球之前到達的情況。

運行時會發生以下情況:

ceverett@changa:~/Code/erlang$ ./pingpong 2
<0.5.0>: Starting pingpong script. Will iterate 2 times.
<0.61.0>: Sending ping to <0.62.0>
<0.62.0>: Sending ping to <0.61.0>
<0.61.0>: Sending ping to <0.62.0>
<0.62.0>: Sending ping to <0.61.0>
<0.61.0>: Received ping from <0.62.0>. Replying with pong.
<0.62.0>: Received ping from <0.61.0>. Replying with pong.
<0.61.0>: Received ping from <0.62.0>. Replying with pong.
<0.62.0>: Received ping from <0.61.0>. Replying with pong.
<0.61.0>: Received pong.
<0.62.0>: Received pong.
<0.61.0>: Received pong.
<0.62.0>: Received pong.
<0.61.0>: Received exit message from <0.5.0>. Retiring.
<0.62.0>: Received exit message from <0.5.0>. Retiring.
<0.5.0>: <0.61.0> is done.
<0.5.0>: <0.62.0> is done.
<0.5.0>: All done, Returing.

如果您運行幾次(或在繁忙的運行時),則某些輸出可能會以不同的順序運行。 這僅僅是並發的本質。

如果您是Erlang的新手,那么上面的代碼可能要花點時間才能理解。您可以自己嘗試使用該乒乓腳本。 編輯它。 讓它做新的事情。 創建一個三角形的ping過程。 產生一個隨機的講話者行事,這些講話者做奇怪的事情。 一旦您弄亂了它,這將突然變得有意義。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM