【问题标题】:How do you regulate concurrency/relative process performance in Erlang?你如何在 Erlang 中调节并发/相对进程的性能?
【发布时间】:2011-09-09 20:20:59
【问题描述】:

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

如果是 Java 或 C++ 等,我可能会这样做(希望这是有道理的):

(File read & xml parsing process) -> bounded-queue -> (sender process) -> service

service -> bounded-queue -> (process to parse result and write to disk)

然后我会为每个进程分配合适数量的线程。这样我可以将每个进程的并发限制在其最佳值,并且有界队列将确保不会出现内存短缺等情况。

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

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

【问题讨论】:

    标签: multithreading performance concurrency erlang


    【解决方案1】:

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

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

    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.
    

    这是一个进程如何限制它产生的进程数量的粗略草图。然而,最好限制真实的原因而不是人为的数字。

    【讨论】:

      【解决方案2】:

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

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

      【讨论】:

      • 感谢您的回答!如果我关心的不是记忆,例如如果我想以特定的并发性与服务交谈,那么使用进程池好吗? edit:我想我从 DefLog 得到了答案
      • 他基本上得出了和我一样的结论。并且基于固定数量的进程进行限制没有真正的意义,这实际上并不能告诉你一些事情(除非这是你的确切要求:同时不超过 N 个并发任务)。
      【解决方案3】:

      我建议你在事件驱动范式中这样做。

      假设您使用文件名列表启动 OTP gen_server。

      1. gen_servers 检查资源并在允许的情况下生成下一个工作人员,从列表中删除文件名并将其传递给工作人员。

      2. Worker 处理文件并在准备好时将消息转换回 gen_server(或者您可以只捕获 EXIT)。

      3. gen_server 收到此类消息并执行步骤 1,直到文件列表为空。

      所以工作人员完成繁重的工作,gen_server 控制流程。

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

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

      【讨论】:

      • 这是否意味着 gen_server 中有某种信号量并集中控制并发等?
      • 我不确定内部实现,但 Erlang 消息传递确实类似于具有无限队列容量的消费者/生产者模型(生产者从不阻塞),通常使用信号量实现。
      猜你喜欢
      • 1970-01-01
      • 2021-05-27
      • 2010-09-11
      • 2015-02-16
      • 2010-11-19
      • 2011-02-10
      • 2010-09-14
      • 2022-01-09
      相关资源
      最近更新 更多