如何获得并发函数(pmap)来使用Elixir中的所有核心?

我开始阅读Dave Thomas的优秀编程Elixir . 我很好奇我能在多大程度上采用"pmap"函数的并发性,所以我迭代地将项目数量从1,000增加到10,000,000 . 出于好奇,我观察了 htop 的输出,因为我这样做,通常是CPU使用率类似于下面显示的:

htop output

在显示书中的例子后,戴夫说:

是的,我刚刚启动了1,000个后台进程,并且使用了我机器上的所有内核和处理器 .

我的问题是,为什么我的机器上只有核心1,3,5和7点亮了?我的猜测是,它与我的 iex 进程只是一个操作系统级进程有关,OSX正在管理该进程的范围 . 那是怎么回事?有没有办法确保所有内核都用于执行性能密集型任务?

回答(2)

2 years ago

@Thiago Silveira关于iex输出第一行的好评 . 部分 [smp:8:8] 表示Erlang使用了多少操作系统级进程 . 如果要禁用它,可以使用标志 --smp 来控制它:

iex --erl '-smp disable'

这将确保您只有一个系统进程 . 您可以通过启用对称多处理来实现类似的结果,但直接设置 NumberOfShcedulers:NumberOfSchedulersOnline .

iex --erl '+S 1:1'

每个操作系统进程都需要有自己的Erlang进程调度程序,因此您可以轻松查看当前有多少个进程:

:erlang.system_info(:schedulers_online)

回答关于表现的问题 . 如果您的处理器没有满负荷运行(100%)而且没有处理器(0%),则很可能使负载分布更均匀不会加快速度 . 为什么?

通过在许多时间点探测处理器状态来测量CPU使用率 . 这种状态要么“工作”要么“闲置” . 82%的CPU使用率意味着您可以在此CPU上执行更多任务,而不会降低其他任务的速度 .

Erlang调度程序试图变得聪明,并且不会在核心之间迁移Erlang进程,除非它们需要复制 . 例如,当其中一个调度程序空闲时,就会发生迁移 . 然后它可以从其他调度程序运行队列借用一个进程 .

接下来可能导致奇数和偶数核心之间存在巨大差异的是超线程 . 在我的双核处理器 htop 上显示了4个逻辑核心 . 在您的情况下,由于HT,您可能有4个物理核心和8个逻辑核心 . 可能是您正在使用100%的物理核心 .

另一件事:pmap需要在单独的进程中计算结果,但最后它将它发送给调用者,这可能是一个瓶颈 . 发送消息的次数越多,可以实现的CPU利用率越低 . 您可以尝试为流程提供一个非常耗费CPU的任务,例如计算Ackerman function . 您甚至可以使用Amdahl's law计算您的工作量是多少,也可以计算不同数量的核心的执行时间 .

总结一下:截图的CPU利用率看起来真的很棒!您不必为更多性能密集型任务更改任何内容 .

2 years ago

Concurrency is not Parallelism

为了从Elixir / BEAM编码中获得良好的并行性能,您需要了解BEAM调度程序的工作原理 .

这是一个非常简单的模型,但是BEAM调度程序在为下一个进程交换进程之前为每个进程提供了2000个减少 . 减少可以被认为是函数调用 . 默认情况下,进程在生成它的核心/调度程序上运行 . 如果未完成进程的队列在给定的调度程序上构建,则进程仅在调度程序之间移动 . 默认情况下,BEAM在每个可用核心上运行调度线程 .

这意味着,为了充分利用处理器,您需要将您的任务分解成足够大的工作量,这些工作量将超过标准的“减少”工作量 . 通常,当您将许多项目分成单个任务时,pmap样式并行性只会提供显着的加速 .

需要注意的另一件事是BEAM的某些部分在等待工作时使用旋转/等待循环,并且当您使用像 htop 这样的工具来检查CPU使用情况时,可能会扭曲使用 . 你'll get a much better understanding of your program'使用 :observer 的表现 .