Erlang - 进程过多

3

这是我在Erlang中的第一步,所以对于这个新手问题很抱歉:) 我为每一个Redis请求生成一个新的Erlang进程,这不是我想要的(在32k Erlang进程时出现“过多的进程”),但是如何将进程的数量限制为最大16个呢?

-module(queue_manager).
-export([add_ids/0, add_id/2]).

add_ids() ->
    {ok, Client} = eredis:start_link(),
    do_spawn(Client, lists:seq(1,100000)).

do_spawn(Client, [H|T]) ->
    Pid = spawn(?MODULE, add_id, [Client, H]),
    do_spawn(Client, T);

do_spawn(_, []) -> none.

add_id(C, Id) ->
    {ok, _} = eredis:q(C, ["SADD", "todo_queue", Id]).

2
您可以使用+P标志可选地增加进程数量:http://erlang.org/pipermail/erlang-questions/2002-December/006329.html - hexist
4个回答

6
尝试使用 Erlang pg2 模块。它允许您轻松创建进程组,并提供了一个 API 来获取组中“最接近”(或随机的)PID。下面是 eredis 客户端的进程组示例:
-module(redis_pg).

-export([create/1,
         add_connections/1, 
         connection/0,
         connections/0,
         q/1]).

create(Count) ->
    % create process group using the module name as the reference
    pg2:create(?MODULE),
    add_connections(Count).

% recursive helper for adding +Count+ connections
add_connections(Count) when Count > 0 ->
    ok = add_connection(),
    add_connections(Count - 1);
add_connections(_Count) -> 
    ok.

add_connection() ->
    % start redis client connection
    {ok, RedisPid} = eredis:start_link(),
    % join the redis connection PID to the process group
    pg2:join(?MODULE, RedisPid).

connection() ->
    % get a random redis connection PID
    pg2:get_closest_pid(?MODULE).

connections() ->
    % get all redis connection PIDs in the group
    pg2:get_members(?MODULE).

q(Argv) ->
    % execute redis command +Argv+ using random connection
    eredis:q(connection(), Argv).

这是上述模块的示例:
1> redis_pg:create(16).
ok
2> redis_pg:connection().
<0.68.0>
3> redis_pg:connection().
<0.69.0>
4> redis_pg:connections().
[<0.53.0>,<0.56.0>,<0.57.0>,<0.58.0>,<0.59.0>,<0.60.0>,
 <0.61.0>,<0.62.0>,<0.63.0>,<0.64.0>,<0.65.0>,<0.66.0>,
 <0.67.0>,<0.68.0>,<0.69.0>,<0.70.0>]
5> redis_pg:q(["PING"]).  
{ok,<<"PONG">>}

你可能想要添加监控以恢复崩溃的连接。你如何确保你得到的组成员没有忙碌?你正在接近一个管理两者的连接池。 - Tilman
将进程监控添加到eredis连接的“DOWN”消息中是一个好主意,这样您就可以重新将连接添加到组中。如果您想要最不繁忙的连接,可以修改connection函数,迭代所有pg成员并使用erlang:process_info(Pid, message_queue_len)查找具有最小队列的进程。 - lastcanal

2

1

在实现限制时,你基本上是“自己一个人”。虽然有一些工具可以帮助你,但我认为总体问题“如何避免生成过多的进程?”仍然存在。诀窍是要在某个地方跟踪进程计数。

一种Erlang惯用的方法是拥有一个包含计数器的进程。每当你想要生成新进程时,你向它注册需要令牌的需求,以此询问是否允许这样做。然后等待计数进程回复你。

计数进程是一个很好的模块化的家伙,为你维护一个限制。


1

您可以使用监督器来启动每个新进程(对于您的示例,似乎应该使用简单的一对一策略):

supervisor:start_child(SupRef, ChildSpec) -> startchild


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接