gpt4 book ai didi

concurrency - 如果 gen_server 进程中的 init/1 函数向自己发送一条消息,它是否保证在任何其他消息之前到达?

转载 作者:行者123 更新时间:2023-12-03 22:35:53 25 4
gpt4 key购买 nike

我偶尔会看到一种模式,其中 init/1 gen_server 的函数进程将向自身发送一条消息,表明它应该被初始化。这样做的目的是为了 gen_server进程异步初始化自身,以便产生它的进程不必等待。下面是一个例子:

-module(test).
-compile(export_all).

init([]) ->
gen_server:cast(self(), init),
{ok, {}}.

handle_cast(init, {}) ->
io:format("initializing~n"),
{noreply, lists:sum(lists:seq(1,10000000))};
handle_cast(m, X) when is_integer(X) ->
io:format("got m. X: ~p~n", [X]),
{noreply, X}.

b() ->
receive P -> {} end,
gen_server:cast(P, m),
b().

test() ->
B = spawn(fun test:b/0),
{ok, A} = gen_server:start_link(test,[],[]),
B ! A.

该过程假定 init消息将在任何其他消息之前收到 - 否则它将崩溃。这个过程有没有可能得到 m init之前的留言信息?

假设没有进程向 list_to_pid 生成的随机 pid 发送消息,因为无论这个问题的答案如何,任何执行此操作的应用程序都可能根本无法运行。

最佳答案

问题的理论答案是否可能为 在 init 消息之前获取消息的过程?是 .
但实际上(当没有进程执行 list_to_pid 并发送消息时)这个进程的答案是 假设 gen_server 不是注册进程。

这是因为 gen_server:start_link 的返回保证了 gen_server 的回调 init 被执行。因此,初始化消息是进程消息队列中在任何其他进程获得 Pid 发送消息之前的第一条消息。 因此,您的进程是安全的,并且在 init 之前不会收到任何其他消息。

但是对于已注册的进程,情况并非如此,因为即使在完成回调 init 函数之前,也可能有一个进程可能会使用注册名称向 gen_server 发送消息。
让我们考虑这个测试函数。

test() ->
Times = lists:seq(1,1000),
spawn(gen_server, start_link,[{local, ?MODULE}, ?MODULE, [], []]),
[gen_server:cast(?MODULE, No) || No <-Times].

样本输出是
1> async_init:test().
Received:356
Received:357
[ok,ok,ok,ok,ok,ok,ok,ok,ok,ok,ok,ok,ok,ok,ok,ok,ok,ok,ok,
ok,ok,ok,ok,ok,ok,ok,ok,ok,ok|...]
Received:358
Received:359
2> Received:360
2> Received:361
...
2> Received:384
2> Received:385
2> Initializing
2> Received:386
2> Received:387
2> Received:388
2> Received:389
...

可以看到 gen_server 在初始化之前收到了 356 到 385 条消息。
因此异步回调在注册名称场景中不起作用。

这可以通过两种方式解决

1.Pid返回后注册进程。

 start_link_reg() ->
{ok, Pid} = gen_server:start(?MODULE, [], []),
register(?MODULE, Pid).


2.或者在handle_cast中为init消息注册进程。

handle_cast(init, State) ->
register(?MODULE, self()),
io:format("Initializing~n"),
{noreply, State};


此更改后的示例输出为
1> async_init:test().
Initializing
Received:918
Received:919
[ok,ok,ok,ok,ok,ok,ok,ok,ok,ok,ok,ok,ok,ok,ok,ok,ok,ok,ok,
ok,ok,ok,ok,ok,ok,ok,ok,ok,ok|...]
Received:920
2> Received:921
2> Received:922
...

因此,向自身发送用于初始化的消息并不能确保它是它接收到的第一个消息,但是代码(和设计)中的一些更改可以确保它是第一个被执行的。

关于concurrency - 如果 gen_server 进程中的 init/1 函数向自己发送一条消息,它是否保证在任何其他消息之前到达?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17997302/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com