【问题标题】:erlang mixing sync and async functionserlang混合同步和异步功能
【发布时间】:2013-11-29 00:17:47
【问题描述】:

是否可以阻止同步函数(handle_call)等待不同模块中的异步调用(handle_cast)?

即 如何让同步函数等待(即阻塞),直到收到来自异步函数的特定“完成”消息? (然后才继续执行) 两个模块都遵循 gen_server 和 gen_fsm 行为。

handle_info 可以以某种方式使用吗?

问候 /彼得

【问题讨论】:

    标签: asynchronous erlang erlang-otp


    【解决方案1】:

    这样做的方法是在handle_call 中保存对发件人的引用,并在稍后调用gen_server:reply。也就是说,虽然您通常会像这样编写 handle_call 函数:

    handle_call(foo, _From, State) ->
        {reply, {ok, bar}, State}.
    

    你会做这样的事情:

    handle_call(foo, From, State = #state{pending = Pending}) ->
        NewState = State#state{pending = [From | Pending]},
        {noreply, NewState}.
    

    然后,也许在handle_info

    handle_info({bar_event, Data}, State = #state{pending = [Head | Tail]) ->
        gen_server:reply(Head, {ok, Data}),
        NewState = State#state{pending = Tail},
        {noreply, NewState}.
    

    这意味着当一个进程调用gen_server:call(Pid, foo)时,它会阻塞,直到服务器进程收到{bar_event, Data},此时服务器会将事件中包含的数据返回给调用者。

    我试图通过将有关调用者的信息存储在“堆栈”中来保持示例的简单性,因此在多个并发调用者的情况下,最后一个调用者将首先返回,反之亦然。在许多情况下,您会希望使用某种键来保存调用方信息,以便在收到异步事件时进行查找。

    这也可以在 gen_fsm 进程中完成;函数调用和返回值类似。

    【讨论】:

    • 谢谢!这正是我所需要的。我已经完全忘记了 {noreply, ... }“return”。
    • 要小心这样做,因为gen_server:call 有 5 秒的内置超时,之后会自动生成错误。可以使用第三个参数设置超时长度,毫秒或infinity
    • 是的,我在之前的应用程序中遇到了这个问题。现在我通常要么设置无穷大,要么传递一个超时值(用于回调。)但这确实让事情有点“混乱”:(
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多