Multithreading 如何在Erlang中调节并发性/相对进程性能?

Multithreading 如何在Erlang中调节并发性/相对进程性能?,multithreading,performance,concurrency,erlang,Multithreading,Performance,Concurrency,Erlang,比方说,我必须从一个包含许多大型XML文件的目录中读取数据,然后对其进行解析,并通过网络将其发送到某个服务,然后再次将响应写入磁盘 进程_标志(陷阱_退出,真), 池(0,最大值); 池(当前,最大)-> 接收 {'EXIT',{,}-> 池(当前-1,最大值); {work,F,Pid}当前 Pid!认可的, 产卵链接(F), 池(当前+1,最大值); {work,u,Pid}-> Pid!拒绝, 池(当前,最大); 结束。 这是一个流程如何限制其生成的流程数量的粗略示意图。然而,人们认为

比方说,我必须从一个包含许多大型XML文件的目录中读取数据,然后对其进行解析,并通过网络将其发送到某个服务,然后再次将响应写入磁盘

<如果是java或C++等,我可能会做这样的事情(希望这是有意义的):

然后我会为每个进程分配合适数量的线程。通过这种方式,我可以将每个进程的并发性限制在其最佳值,并且有界队列将确保不会出现内存不足等问题

在Erlang中编写代码时应该怎么做?我想我可以在一个函数中实现整个流程,然后迭代目录并尽快生成这些“从开始到结束”的流程。不过,这听起来不太理想,因为如果解析XML比读取文件等花费的时间更长,那么应用程序就会停止。由于同时在内存中有许多XML文档等原因,可能会导致内存不足,并且无法将并发性保持在最佳水平。例如,如果“服务”在并发度为4时效率最高,那么用巨大的并发性来攻击它将是非常低效的


erlang程序员应该如何处理这种情况?例如,什么是erlang替代固定线程池和有界队列?

您当然可以在erlang中运行自己的进程池,但这是一种糟糕的内存使用方式,因为它没有考虑正在读取的XML数据的大小(或进程为此使用的总内存)


我建议按照您的建议,在功能库中实现整个工作流,并生成执行此工作流的流程。添加内存使用检查,检查要读取的数据的大小和可用内存(提示:使用)。

没有真正的方法限制进程的队列大小,除非及时处理它们。最好的方法是在产卵前检查可用资源,如果资源不足,则等待。因此,如果您担心内存问题,请在生成新进程之前检查内存。如果是磁盘空间,请检查磁盘空间等

限制生成的进程数量也是可能的。一个简单的结构是:

pool(Max) -> 
    process_flag(trap_exit, true),
    pool(0, Max);
pool(Current, Max) ->
    receive
        {'EXIT', _, _} -> 
            pool(Current - 1, Max);
        { work, F, Pid} when Current < Max -> 
            Pid ! accepted,
            spawn_link(F),
            pool(Current + 1, Max);
        { work, _, Pid} -> 
            Pid ! rejected,
            pool(Current, Max);
    end.
池(最大)->
进程_标志(陷阱_退出,真),
池(0,最大值);
池(当前,最大)->
接收
{'EXIT',{,}->
池(当前-1,最大值);
{work,F,Pid}当前<最大值->
Pid!认可的,
产卵链接(F),
池(当前+1,最大值);
{work,u,Pid}->
Pid!拒绝,
池(当前,最大);
结束。

这是一个流程如何限制其生成的流程数量的粗略示意图。然而,人们认为最好限制真实的原因,而不是人为的数字。

我建议您在事件驱动的范例中这样做

假设您使用文件名列表启动OTP gen_服务器

  • gen_服务器检查资源并生成下一个工作进程(如果允许),从列表中删除文件名并将其传递给工作进程

  • 工作进程处理文件,并在准备就绪时将消息返回给gen_服务器(或者您可以直接退出陷阱)

  • gen_服务器接收此类消息并执行步骤1,直到文件列表为空

  • 工人们负责搬运重物,gen_服务器控制流量

    您也可以创建分布式系统,但这有点复杂,因为您需要在每台计算机上生成中间gen_服务器,并查询它们是否有可用的资源,然后根据回复选择哪台计算机应处理下一个文件。您可能需要NFS之类的东西来避免发送长消息


    如果您需要更多的并发性,可以进一步拆分工作线程。

    谢谢您的回答!如果我关心的不是内存,例如,如果我想以特定的并发性与服务通信,那么使用进程池是否合适?编辑:我想我是从Deblog那里得到答案的。他得出的结论基本上和我一样。基于固定数量的进程进行限制是没有实际意义的,这实际上并没有告诉你一些事情(除非这是你的确切要求:同一时间不超过N个并发任务)。这是否意味着gen_服务器中有某种信号量并集中控制并发性等?我不确定内部实现,但Erlang消息传递确实类似于具有无限队列容量(生产者从不阻塞)的消费者/生产者模型,通常使用信号量实现。
    pool(Max) -> 
        process_flag(trap_exit, true),
        pool(0, Max);
    pool(Current, Max) ->
        receive
            {'EXIT', _, _} -> 
                pool(Current - 1, Max);
            { work, F, Pid} when Current < Max -> 
                Pid ! accepted,
                spawn_link(F),
                pool(Current + 1, Max);
            { work, _, Pid} -> 
                Pid ! rejected,
                pool(Current, Max);
        end.