Enn*_*oji 5 concurrency erlang optimization performance
TL;博士
我得到更好的性能与我的二郎程序,当我在更高的并发执行我的CPU密集型任务(如10K一次比4).为什么?
我正在使用erlang编写一个map reduce框架,我正在进行性能测试.
我的地图功能是高度CPU密集型的(主要是纯计算).它还需要访问一些静态数据,因此我在我的机器上有一些持久的(延迟,即通过应用程序.生命周期生活)工作进程,每个工作进程都有内存中的数据,并等待映射请求.map的输出被发送到管理器进程(向工作人员发送映射请求),其中执行reduce(非常轻量级).
无论如何,当我立即为工作人员收到的每个地图请求生成一个新进程时,我注意到我的吞吐量越来越高,而不是让工作进程本身逐个地同步执行地图请求(因此留下了一堆)其进程队列中的映射请求,因为我一次性触发映射请求).
代码段:
%% When I remove the comment, I get significant performance boost (90% -> 96%)
%% spawn_link(fun()->
%% One invocation uses around 250ms of CPU time
do_map(Map, AssignedSet, Emit, Data),
Manager ! {finished, JobId, self(), AssignedSet, normal},
%% end),
Run Code Online (Sandbox Code Playgroud)
与在紧密循环中执行相同计算的情况相比,使用"立即生成"方法获得96%的吞吐量(效率)(例如,10000个映射减少作业完全并行运行).当我使用"工人逐个执行"的方法时,我只得到90%左右.
我知道Erlang应该擅长并发的东西,我印象深刻的是,即使我一次执行10K map reduce请求而不是100等,效率也不会改变!但是,由于我只有4个CPU内核,如果我使用较低的并发性(如4或5),我希望能获得更好的吞吐量.
奇怪的是,我的CPU使用率在两种不同的实现中看起来非常相似(在所有内核上几乎完全固定为100%).性能差异非常稳定.即使我只做了100个地图减少工作,我仍然使用"立即生成"方法获得96%左右的效率,当我使用"逐个"方法时,效率约为90%.同样,当我测试200,500,1000,1000个工作时.
我首先怀疑在工作进程队列中排队是罪魁祸首,但即使我在工作进程队列中只有25条消息,我仍然看到性能较低.25个消息似乎非常小,导致阻塞(我正在进行选择性消息匹配,但不是过程必须将消息放回队列).
我不知道该如何从这里开始.我做错了什么,还是我完全错过了什么?
UPDATE
我做了一些测试,发现性能差异可能会根据条件消失(特别是我分割静态数据的工作进程数).看起来我还有很多东西需要学习!
假设 1 个工作进程有 3 个映射操作,我们有第一个变体:
_______ _______ _______
| m | | m | | m |
| | | | | |
_| |_| |_| |_
a a a r
Run Code Online (Sandbox Code Playgroud)
a管理任务(从消息队列读取、调度映射等)在哪里m是实际的映射并r正在发送回结果。第二种变体是为每个地图生成一个进程:
_________________._
| m r
| ___________________._
| | m r
| | _____________________._
_|_|_| m r
a a a
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,管理任务 ( a) 与地图 ( m) 以及发回结果 ( r) 的时间相同。
这将使 CPU 始终忙于映射(即计算密集型)工作,而不是时不时地出现短暂的下降。这很可能是您在吞吐量中看到的小幅增益。
由于从一开始就具有相当高的并发性,因此您只能看到吞吐量的相对较小的增益。与理论上仅运行一个工作进程(如第一个变体)相比,您会看到更大的收益。
| 归档时间: |
|
| 查看次数: |
800 次 |
| 最近记录: |