【问题标题】:Erlang - too many processesErlang - 进程太多
【发布时间】:2012-10-13 13:56:14
【问题描述】:

这些是我在 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]).

【问题讨论】:

标签: exception concurrency erlang process


【解决方案1】:

尝试使用 Erlang pg2 module。它允许您轻松创建进程组并提供 API 来获取组中“最近”(或随机)的 PI​​D。

这是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">>}

【讨论】:

  • 您可能希望添加监管以恢复崩溃的连接。你如何确保你得到的小组成员不忙?您正在接近管理两者的连接池。
  • 为 'DOWN' 消息添加进程监控到 eredis 连接是个好主意,这样您就可以重新添加到组的连接。如果您想要最不繁忙的连接,您可以修改 connection 函数以遍历所有 pg 成员并使用 erlang:process_info(Pid, message_queue_len). 找到具有最小队列的进程
【解决方案2】:

您可以使用连接池,例如eredis_poolThis is a similar question 你可能会感兴趣。

【讨论】:

    【解决方案3】:

    您可以使用主管来启动每个新流程(对于您的示例,您似乎应该使用 simple_one_for_one 策略):

    supervisor:start_child(SupRef, ChildSpec) -&gt; startchild_ret()

    然后你可以使用函数访问进程计数

    supervisor:count_children(SupRef) -&gt; PropListOfCounts

    结果是表单的proplist

    [{specs,N1},{active,N2},{supervisors,N3},{workers,N4}](不保证顺序!)

    如果你想了解更多关于活动进程的信息,你也可以使用

    supervisor:which_children(SupRef) -&gt; [{Id, Child, Type, Modules}] 但当主管管理“大量”孩子时不建议这样做。

    【讨论】:

      【解决方案4】:

      当您实施限制时,您基本上是“靠自己”。有一些工具可以帮助你,但我认为一般问题是“如何避免产生太多进程?”仍然成立。诀窍是在某处跟踪进程计数。

      Erlang 惯用的方法是拥有一个包含计数器的进程。每当您想生成一个新进程时,您都会通过注册对令牌的需求来询问它是否允许这样做。然后,您等待计数过程回复您。

      然后,计数过程是一个很好的模块化人,为您维护一个限制。

      【讨论】:

        猜你喜欢
        • 2017-10-30
        • 2012-04-06
        • 1970-01-01
        • 2019-08-19
        • 2013-04-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-11-29
        相关资源
        最近更新 更多