Concurrency 循环发送消息。

Concurrency 循环发送消息。,concurrency,erlang,Concurrency,Erlang,我是函数式编程新手,刚从haskell(不太喜欢)转到erlang(非常喜欢)。当我作为一个自学成才的人学习时,我绊倒了,开始做这些事情 我谈到了这个问题: 编写一个函数,启动两个进程,并发送消息M 时间在他们之间向前和向后。在消息发出后 发送后,进程应正常终止 我是这样解决的,而且效果很好(也许可以做得更好;任何评论都非常感谢): 真正的问题是下一个练习: 2) 编写一个函数,在一个环中启动N个进程,并发送一个 消息在环中的所有进程中循环M次。之后 消息已发送,进程应正常终止 由于我没有将消息

我是函数式编程新手,刚从haskell(不太喜欢)转到erlang(非常喜欢)。当我作为一个自学成才的人学习时,我绊倒了,开始做这些事情

我谈到了这个问题:

  • 编写一个函数,启动两个进程,并发送消息M 时间在他们之间向前和向后。在消息发出后 发送后,进程应正常终止
  • 我是这样解决的,而且效果很好(也许可以做得更好;任何评论都非常感谢):

    真正的问题是下一个练习:

    2) 编写一个函数,在一个环中启动N个进程,并发送一个 消息在环中的所有进程中循环M次。之后 消息已发送,进程应正常终止

    由于我没有将消息发送回其发起者,而是发送到链中的下一个节点,因此我必须以某种方式将收件人的流程传递给发送流程。所以我想象这个函数会是这样的:

    pingCircle (Name, Next) ->
    ...
        receive {TTL, Msg} -> Next ! {TTL - 1, Msg}
    ...
    
    但我该如何开始这整件事呢。当我生成圆中的第一个函数时,我仍然没有生成下一个节点,因此无法将其作为参数传递。所以我的天真方法不起作用:

    First = spawn (concur, pingCirle, ["Alice", Second] ),
    Second = spawn (concur, pingCirle, ["Bob", Third] ),
    ...
    
    同样,将下一个节点的spawn调用作为参数递归传递给它的前置节点的方法也不能解决如何闭合圆的问题,即将最后一个节点传递给第一个节点

    问题是: 我怎样才能建立这个圈子

    编辑:

    多亏了你的精彩回答,我终于达到了我的目的。于是这个问题就解决了

    一种可能的解决办法是:

    -module (concur).
    -export ( [pingCircle/3, pingCircle/2] ).
    
    pingCircle (Names, Message, TTL) ->
        Processes = lists:map (fun (Name) -> spawn (?MODULE, pingCircle, [Name, nobody] ) end, Names),
        ProcessPairs = lists:zip (Processes, rot1 (Processes) ),
        lists:map (fun ( {Process, Recipient} ) -> Process ! {setRecipient, Recipient} end, ProcessPairs),
        Circle = lists:map (fun ( {Process, _} ) -> Process end, ProcessPairs),
        hd (Circle) ! {Message, TTL - 1, lists:last (Circle) }.
    
    rot1 ( [] ) -> [];
    rot1 ( [Head | Tail] ) -> Tail ++ [Head].
    
    pingCircle (Name, Recipient) ->
        receive
            {setRecipient, NewRecipient} ->
                pingCircle (Name, NewRecipient);
            {Message, 0, Originator} ->
                io:format ("~s received ~p with TTL 0 and dying.~n", [Name, Message] ),
                if
                    Originator == self () -> io:format ("All dead.~n");
                    true -> Recipient ! {Message, 0, Originator}
                end;
            {Message, TTL, Originator} ->
                io:format ("~s received ~p with TTL ~p.~n", [Name, Message, TTL] ),
                if
                    Originator == self () -> Recipient ! {Message, TTL - 1, Originator};
                    true -> Recipient ! {Message, TTL, Originator}
                end,
                pingCircle (Name, Recipient)
        end.
    

    这是我的。

    首先生成它们,然后向它们发送启动信号


    启动信号将在所有进程都已运行后发送。

    这里已经有人给出了答案->

    这一练习已成为所有erlang程序员的一种仪式。我给出了一个可行的解决方案,以及一个可能有用的解释。

    我的答案

    -module(con_test).
    
    start_ring(Msg, M, N) ->
        [First|_]=Processes=[spawn(?MODULE, ring, []) || _ <- lists:seq(1,N)],
        First ! {rotLeft(Processes), {Msg, M*N}}.
    
    ring() ->
        receive
            {_List, {Msg, Count}} when Count == 0 ->
                io:format("~p got ~s. Enough! I'm out.~n", [self(), Msg]),
                exit(normal);
            {[Next|_] = List, {Msg, Count}} when Count > 0 ->
                io:format("~p got ~s. Passing it forward to ~p.~n", [self(), Msg, Next]),
                Next ! {rotLeft(List), {Msg, Count-1}},
                ring()
        after 1000 ->
            io:format("~p is out.~n", [self()]),
            exit(normal)
        end.
    
    rotLeft([])     ->  [];
    rotLeft([H|T])  ->  T ++[H].
    
    -模块(con_测试)。
    启动铃声(Msg,M,N)->
    [First | |]=进程=[spawn(?模,环,[])| | |
    接收
    {{u List,{Msg,Count}}当Count==0->
    io:format(“~p有~s.够了!我出去了。~n”,[self(),Msg]),
    出口(正常);
    {[Next |}=List,{Msg,Count}当Count>0->
    io:format(~p获得~s.将其转发给~p.~n),[self(),Msg,Next]),
    下一个!{rotleet(List),{Msg,Count-1},
    环()
    1000后->
    io:format(“~p已输出。~n”,[self()]),
    出口(正常)
    结束。
    左旋转([])->[];
    旋转左([H | T])->T++[H]。
    
    +1只是为了自动教学。顺便说一句,如果你想对已经正确的代码提出建设性的批评,你可以随时尝试。+1评论-这很酷,谢谢你的信息!+1也来自我。这将有助于解决这个新的语言。+1非常酷。我本可以在阅读这些内容时使用它!非常感谢你。但是在阅读了“成年礼”一词我不敢看你的解决方案,但通过@Michael的输入,我自己通过了这个仪式。我更新了我的帖子,将把我的代码上传到codereview.stackexchange.com,我非常感谢你的评论。我非常感谢你对我的评论。欢迎你——祝贺你完成了这个练习。考虑到您对该语言有多陌生。总体而言,您的解决方案看起来不错-如果我有具体的评论,我会将它们发布在codereview上。大多数解决方案和我的解决方案的主要区别在于,我解决了一个稍微难一点的问题,即让戒指自行创建。我认为我自己的解决方案可能需要可读性部门的一些帮助。如果我想出更好的办法我会把它贴在这里。谢谢,这是我需要想出自己的解决方案的地方。我更新了我的帖子。我会感谢你的评论。非常感谢,但在@Michael的输入之后,我宁愿继续独自尝试。
    -module(con_test).
    
    start_ring(Msg, M, N) ->
        [First|_]=Processes=[spawn(?MODULE, ring, []) || _ <- lists:seq(1,N)],
        First ! {rotLeft(Processes), {Msg, M*N}}.
    
    ring() ->
        receive
            {_List, {Msg, Count}} when Count == 0 ->
                io:format("~p got ~s. Enough! I'm out.~n", [self(), Msg]),
                exit(normal);
            {[Next|_] = List, {Msg, Count}} when Count > 0 ->
                io:format("~p got ~s. Passing it forward to ~p.~n", [self(), Msg, Next]),
                Next ! {rotLeft(List), {Msg, Count-1}},
                ring()
        after 1000 ->
            io:format("~p is out.~n", [self()]),
            exit(normal)
        end.
    
    rotLeft([])     ->  [];
    rotLeft([H|T])  ->  T ++[H].