Concurrency erlang进程和消息传递体系结构

Concurrency erlang进程和消息传递体系结构,concurrency,process,erlang,messages,Concurrency,Process,Erlang,Messages,我手头的任务是读取大文件的行,处理它们,并返回有序的结果 我的算法是: 从评估工作负载的主流程开始(写在文件的第一行) 生成工作进程:每个工作进程将使用pread/3读取文件的一部分,处理该部分,并将结果发送给master master接收所有子结果、排序和返回 因此,工人之间基本上不需要沟通 我的问题: 如何在erlang进程数和内核数之间找到最佳平衡?所以,如果我为我拥有的每个处理器核心生成一个进程,会不会是我的cpu利用率不足 pread/3如何到达指定的行;它是否迭代文件中的所有行?pr

我手头的任务是读取大文件的行,处理它们,并返回有序的结果

我的算法是:

  • 从评估工作负载的主流程开始(写在文件的第一行)
  • 生成工作进程:每个工作进程将使用pread/3读取文件的一部分,处理该部分,并将结果发送给master
  • master接收所有子结果、排序和返回 因此,工人之间基本上不需要沟通
  • 我的问题:

  • 如何在erlang进程数和内核数之间找到最佳平衡?所以,如果我为我拥有的每个处理器核心生成一个进程,会不会是我的cpu利用率不足
  • pread/3如何到达指定的行;它是否迭代文件中的所有行?pread/3是并行文件读取的好计划吗
  • 从进程A向进程B发送一条大消息还是发送N条小消息更好?我在下面的链接中找到了部分答案,但我希望进一步详细说明
  • Erlang进程很便宜。您可以自由(并被鼓励)使用比您拥有的内核数量更多的内核。对您的问题来说,实际操作可能有一个上限(每行在一个进程中加载1TB的数据要求有点高,具体取决于行大小)

    当你不知道的时候,最简单的方法就是让用户决定。这意味着您可以决定产生
    N
    工作者,并在他们之间分配工作,等待回音。如果您不喜欢程序的运行方式,请在更改
    N
    的同时重新运行程序

    更棘手的方法是对大量时间进行基准测试,选择您认为有意义的最大值,将其放入池库中(如果您愿意;一些池用于预分配的资源,一些池用于可调整大小的资源),然后满足于一刀切的解决方案

    但实际上,不存在简单的“最佳核数”。您可以在50个进程上运行它,如果需要,还可以在其中65000个进程上运行它;如果任务是令人尴尬的并行任务,虚拟机应该能够利用它们中的大部分,并使内核饱和

  • -

  • 并行文件读取是一个有趣的问题。它可能会更快,也可能不会更快(正如直接评论所提到的),而且只有在每行的工作量足够小,以至于读取文件的成本最高的情况下,它才可能代表速度的提高

    棘手的是像
    pread/2-3
    这样的函数需要一个字节偏移量。您的问题的措辞使您担心文件的行数。因此,您传递给工人的字节偏移量可能会跨越一行。如果块在
    这是我的行中的单词
    my
    处结束\n当它开始时,一个工作人员将看到自己的行不完整,而另一个工作人员将只报告
    my行\n
    ,缺少前面的
    这是

    一般来说,这类烦人的事情会导致你让第一个进程拥有文件并对其进行筛选,只会将一些文本交给工作人员处理;然后,该进程将充当某种协调人

    此策略的优点在于,如果主进程知道作为消息发送的所有内容,它还知道何时收到所有响应,从而很容易知道何时返回结果。如果一切都是不相交的,那么你必须相信发起者和员工会告诉你“我们都失业了”,这是一组独特的独立信息

    在实践中,您可能会发现,最有帮助的是了解与文件操作相关的有助于硬件使用寿命的do操作,而不是“有多少人可以一次读取文件”。只有一个硬盘(或SSD),所有数据都必须通过它;并行性最终可能会受到限制,以便于访问

  • -

  • 使用对您的程序有意义的消息。性能最好的程序会有很多进程,它们能够在不需要传递消息、通信或获取锁的情况下完成工作

    一个更现实、性能更高的程序将使用非常小的消息

    有趣的是,您的问题本质上是基于数据的。所以你可以做几件事:

    • 确保你阅读的文本是二进制格式的;大型二进制文件(>64b)在全局二进制堆上分配,共享,并使用引用计数进行GC
    • 交上需要做什么的信息,而不是做这件事的数据;这一个需要测量,但前置过程可以遍历文件,注意行的结束位置,只需将字节偏移量交给工作人员,以便他们自己去读取文件;请注意,您最终将读取文件两次,因此如果内存分配不是您的主要开销,那么这可能会更慢
    • 确保以
      raw
      ram
      模式读取文件;其他模式使用中间人进程来读取和转发数据(如果您通过集群Erlang节点中的网络读取文件,这非常有用)
      raw
      ram
      模式将文件描述符直接提供给调用过程,速度更快
    • 首先要担心编写一个清晰、可读且正确的程序。只有当它太慢时,你才应该尝试重构和优化它;第一次尝试,你可能会发现它已经足够好了
  • 我希望这有帮助

    另外,你可以先尝试一些非常简单的东西:

  • 要么:

    • 使用
      {ok,Bin}=file:read_file(Path)
      和拆分行(使用
      binary:split(Bin,[global])
      一次性读取整个文件
    • 使用
      {ok,Io}=file:open(file[read,ram])
      然后在文件描述符上重复使用
      file:read\u line(Io)
    • 使用
      {ok,Io}=file:open(file,[read,raw,{read\u-ahead,BlockSiz