How fast can Erlang send messages?

本文通过实验展示了Erlang环境下消息发送与接收的速度,实现了每秒340万次单向消息传递及每秒140万次往返消息交互。测试在2.8GHz Pentium 4处理器上进行,并探讨了不同系统调用(如poll与epoll_wait)对性能的影响。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原文地址:[url]http://www.lshift.net/blog/2006/09/10/how-fast-can-erlang-send-messages[/url]

My previous post examined Erlang’s speed of process setup and teardown. Here I’m looking at how quickly messages can be sent and received within a single Erlang node. Roughly speaking, I’m seeing 3.4 million deliveries per second one-way, and 1.4 million roundtrips per second (2.8 million deliveries per second) in a ping-pong setup in the same environment as previously - a 2.8GHz Pentium 4 with 1MB cache.

Here’s the code I’m using - time_diff and dotimes aren’t shown, because they’re the same as the code in the previous post:

-module(ipctest).
-export([oneway/0, consumer/0, pingpong/0]).

oneway() ->
N = 10000000,
Pid = spawn(ipctest, consumer, []),
Start = erlang:now(),
dotimes(N - 1, fun () -> Pid ! message end),
Pid ! {done, self()},
receive ok -> ok end,
Stop = erlang:now(),
N / time_diff(Start, Stop).

pingpong() ->
N = 10000000,
Pid = spawn(ipctest, consumer, []),
Start = erlang:now(),
Message = {ping, self()},
dotimes(N, fun () ->
Pid ! Message,
receive pong -> ok end
end),
Stop = erlang:now(),
N / time_diff(Start, Stop).

consumer() ->
receive
message -> consumer();
{done, Pid} -> Pid ! ok;
{ping, Pid} ->
Pid ! pong,
consumer()
end.

dotimes(0, _) -> done;
dotimes(N, F) ->
F(),
dotimes(N - 1, F).

time_diff({A1,A2,A3}, {B1,B2,B3}) ->
(B1 - A1) * 1000000 + (B2 - A2) + (B3 - A3) / 1000000.0 .

我的实验如下:
root@nd-desktop:~/otp_src_R13B01# cat /proc/cpuinfo
processor : 0
vendor_id : GenuineIntel
cpu family : 6
model : 23
model name : Pentium(R) Dual-Core CPU E5200 @ 2.50GHz
stepping : 6
cpu MHz : 1200.000
cache size : 2048 KB
physical id : 0
siblings : 2
core id : 0
cpu cores : 2
apicid : 0
initial apicid : 0
fdiv_bug : no
hlt_bug : no
f00f_bug : no
coma_bug : no
fpu : yes
fpu_exception : yes
cpuid level : 10
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe nx lm constant_tsc arch_perfmon pebs bts pni dtes64 monitor ds_cpl est tm2 ssse3 cx16 xtpr pdcm lahf_lm
bogomips : 4988.06
clflush size : 64
power management:

root@nd-desktop:~# erl -smp disable
Erlang R13B01 (erts-5.7.2) [source] [rq:1] [async-threads:0] [hipe] [kernel-poll:false]

Eshell V5.7.2 (abort with ^G)
1> ipctest:pingpong().
2695648.1187206563
2>
BREAK: (a)bort (c)ontinue (p)roc info (i)nfo (l)oaded
(v)ersion (k)ill (D)b-tables (d)istribution

trace了下发现大部分的系统调用是
poll([{fd=3, events=POLLIN|POLLRDNORM}, {fd=5, events=POLLIN|POLLRDNORM}, {fd=0, events=POLLIN|POLLRDNORM}], 3, 0) = 0 (Timeout)
clock_gettime(CLOCK_MONOTONIC, {3240948, 582336474}) = 0


^Croot@nd-desktop:~# erl
Erlang R13B01 (erts-5.7.2) [source] [smp:2:2] [rq:2] [async-threads:0] [hipe] [kernel-poll:false]

Eshell V5.7.2 (abort with ^G)
1> ipctest:pingpong().
709320.2697346376
2>


root@nd-desktop:~# erl -smp disable +K true
Erlang R13B01 (erts-5.7.2) [source] [rq:1] [async-threads:0] [hipe] [kernel-poll:true]

Eshell V5.7.2 (abort with ^G)
1>
1> ipctest:pingpong().
2801110.2480579205
2>

现在的系统调用是:
clock_gettime(CLOCK_MONOTONIC, {3241209, 575644283}) = 0
epoll_wait(3, {}, 256, 0) = 0
clock_gettime(CLOCK_MONOTONIC, {3241209, 575983781}) = 0
epoll_wait(3, {}, 256, 0)

速度从原来的2695648.1187206563变成现在的2801110.2480579205 有10%的提升, 仅仅是因为系统调用从poll到epoll_wait的改变 进出内核的参数少了。

这个速度已经非常理想了 也就是说消息从ping发出-》pong调度-》pong给ping回ok消息-》ping调度,整个流程才花了大概[color=red]0.4us[/color],这是相当不错的速度。。。

结论: 消息处理很快, 系统调用很费时,beam比beam.smp快很多。

附上erlang进程调度的流程:
1. 处理timer超时
2. 处理子进程退出的情况
3. 处理port_task事件,也就是port的IO事件
4. 如果没有活跃的进程 就sys_schdule阻塞在底层的IO中。
5. 根据process的优先级选出一个进程来调度。

上面epoll_wait的原因就是ping和pong的规约次数到了 让出执行权

附上gdb的断点:

[color=red]/* Pid ! Message,*/[/color]
Breakpoint 2, erts_send_message (sender=0xb7c29aec, receiver=0xb7c2af8c, receiver_locks=0xbfd79790, message=3081450490, flags=0) at beam/erl_message.c:838
838 {
(gdb) c
Continuing.

[color=red]/*receive pong -> ok end*/[/color]
/* ping进程receive的时候阻塞,目前活跃的进程就一个 也就是说pong进程 */
Breakpoint 1, schedule (p=0xb7c29aec, calls=47) at beam/erl_process.c:5785
5785 {
(gdb) c
Continuing.

/* 处理完成消息 释放*/
Breakpoint 3, free_message (mp=0x81f3870) at beam/erl_message.c:53
53 {
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值