zoukankan      html  css  js  c++  java
  • ellang 中进程异步通信中的信箱与保序

    erlang 进程通讯中 执行到 receive 语句时 如果信箱没有消息可以匹配时会暂停等待消息. 

    go() ->
        register(echo, spawn(test_pid,loop,[])),
        echo ! {self(), hello},
        receive
            {_Pid,Msg} ->
                io:format("~w~n",[Msg])
        end.
        %%Pid ! stop.
    
    loop() ->
        io:format(" loop start~n", []),
        receive
            {From, Msg} ->
                io:format(" loop : ~w | ~w~n", [From, Msg]), From ! {self(), Msg},
                loop();
            stop  -> io:format(" loop : ~w~n", [stop]), true
            %%    true
        end.

    由于信箱是先进先出,向同一个进程发送的消息,处理返回一定是保序的。 但这只限于一直不出错,匹配成功的情况,比如 revecie支持 timeOut, timeOut 后 进程将不在主动响应, 但是还能接收信息.

    read(Db, Key) ->
        Db ! {self(), {read, Key}},
        receive
            {read, R} -> {ok, R};
            {error, Reason} -> {error, Reason}
        after 10000 -> {error, timeout}
        end.
    
    db() ->
        receive
            {Pid, {read, 2}} -> Pid ! {read, 2},db();
            {Pid, {read, 3}} -> Pid ! {read, 3},db();
            {Pid, {read, 5}} -> Pid ! {error, "not Reason"},db()
        end.

    假如 有以下调用(Db 是个查询进程,查询完毕会给当前进程返回查询结果)

    read(Db, 1).

    read(Db, 2).

    //after 1500

    read(Db, 6).

    如果 read(Db, 1). 触发了timeout,  而且 read(Db, 2). 返回了{read, R}. 那么这时信箱处于阻塞状态,当read(Db,6).执行时, 会从信箱中取出第一条匹配返回. 所以 read(Db, 6).会返回 {ok, 2}.

    如果是在终端直接运行测试,可以这样写

    read(Db, Key) ->
        Db ! {self(), {read, Key}},
        receive
            {read, R} -> {ok, R};
            {error, Reason} -> {error, Reason}
        after 10000 -> test(self()), {error, timeout}
        end.
    
    db() ->
        receive
            {Pid, {read, 2}} -> Pid ! {read, 2},db();
            {Pid, {read, 3}} -> Pid ! {read, 3},db();
            {Pid, {read, 5}} -> Pid ! {error, "not Reason"},db()
        end.
    
    test(Pid) ->
        Pid ! {read, 2}.

    在timeout 的时候往信箱里塞一条信息,然后你会看到

    所以这时候,信箱的顺序就是错乱的, 那解决办法呢,一种是每次匹配前清理上一条消息,另一种则是加个唯一标识收到消息时匹配下是不是自己要的信息.

  • 相关阅读:
    JDBC事务管理
    JDBC常见操作
    Java集合之List接口
    Nginx+Keepalived+Lvs实现双机热备
    Nginx+Consul+Upsync实现动态负载均衡
    DNS域名解析概念
    WPF中实现两个窗口之间传值
    C# 重写(override)和覆盖(new)
    C# DateTime.Now函数
    WPF中在后台实现控件样式
  • 原文地址:https://www.cnblogs.com/bobolive/p/3171076.html
Copyright © 2011-2022 走看看