unix/linux下的进程间通信有很多种方法,如:
- 匿名管道(pipe):父子进程间的通信
- 命名管道(fifo):可以和无关联进程的通信
- 共享内存(shm):可以和无关联进程的通信,需要自己处理进程同步,比如和信号量配合。
- unix域套接字(unix socket):可以和无关联进程的通信,使用socket接口。
- 网域套接字(internet socket):可以跨主机通信,使用socket接口。
- 等等
这些方案各有自己的特点:
- 比如通常我们能确定共享内存一定是最快的,因为它通过将虚拟内存映射到相同的物理内存,使得两个进程可以操作相同的内存,但是它只是普通的内存操作,需要我们自己处理同步问题,以及如何通知其他进程。总结起来就是不大好用,并且如果加了同步机制之后,性能还会很快吗?
- 匿名管道很好用,不过只能在有关联的进程间使用(父子进程),命名管道可以在任意进程使用,但的性能到底如何?
- unix套接字的好处是使用相同的socket接口,我们可以设计一个抽象层,把它和TCP/UDP统一起来。前提当然是假设它在本机的进程间通信要好于TCP/UDP。
- 网域套接字的好处更明显了,可以本机(使用回环地址),也可以在网络上通信,一套接口通用性很好。
这些IPC方法的吞吐量到底怎么样呢?github上有一个项目对这些方法作了性能测试,不过有一些小问题,我fork了过来修改了一下,并且加上共享内存的测试,放在这里: https://github.com/colinsusie/ipc_benchmark
这里就不贴代码了,直接上测试结果
测试环境是虚拟机:两核的Intel(R) Xeon(R) CPU E5-2680 v3 @ 2.50GHz,系统是debian 8
+------------+--------------+--------------+---------------+---------------+---------------+----------------+
| test/size | 128 x 100000 | 256 x 100000 | 512 x 100000 | 1024 x 100000 | 2048 x 100000 | 4096 x 100000 |
+------------+--------------+--------------+---------------+---------------+---------------+----------------+
| pipe | 186MB/s | 309MB/s | 502MB/s | 848MB/s | 1328MB/s | 1667MB/s |
| fifo | 51MB/s | 90MB/s | 192MB/s | 445MB/s | 1002MB/s | 1837MB/s |
| socketpair | 61MB/s | 148MB/s | 311MB/s | 655MB/s | 952MB/s | 1989MB/s |
| uds | 86MB/s | 146MB/s | 317MB/s | 689MB/s | 922MB/s | 2023MB/s |
| tcp | 97MB/s | 158MB/s | 334MB/s | 578MB/s | 745MB/s | 1014MB/s |
| shm | 4.768381MB/s | 8.698946MB/s | 18.034129MB/s | 35.899021MB/s | 78.708005MB/s | 142.803191MB/s |
+------------+--------------+--------------+---------------+---------------+---------------+----------------+
方法是创建父子进程,由一个进程向另一个进程写100000次数据,数据大小从128到4096。结果很让人差异,fifo的效率比pipe差2倍,而共享内存因为加了信号量之后性能非常差。
上面结果也引来一些人的疑问,为此我找了另一台虚拟机:4核的Intel(R) Xeon(R) CPU E5-26xx v4,,系统是仍然debian 8, 结果如下:
+------------+---------------+----------------+---------------+----------------+---------------+-----------------+
| test/size | 128 x 100000 | 256 x 100000 | 512 x 100000 | 1024 x 100000 | 2048 x 100000 | 4096 x 100000 |
+------------+---------------+----------------+---------------+----------------+---------------+-----------------+
| pipe | 220MB/s | 383MB/s | 672MB/s | 1378MB/s | 2108MB/s | 1641MB/s |
| fifo | 183MB/s | 350MB/s | 654MB/s | 1182MB/s | 1731MB/s | 1751MB/s |
| socketpair | 180MB/s | 343MB/s | 649MB/s | 1161MB/s | 1953MB/s | 2991MB/s |
| uds | 134MB/s | 339MB/s | 549MB/s | 1148MB/s | 2119MB/s | 2776MB/s |
| tcp | 228MB/s | 657MB/s | 1125MB/s | 1805MB/s | 1608MB/s | 2201MB/s |
| shm | 55.320491MB/s | 108.505956MB/s | 35.058660MB/s | 474.144318MB/s | 96.502366MB/s | 1753.450929MB/s |
+------------+---------------+----------------+---------------+----------------+---------------+-----------------+
这回fifo和pipe差不多了,为了验证是否第1台虚拟机有问题,我又找了一个和第1台相同配置的虚拟机(没办法机器多),测试结果如下:
+------------+--------------+--------------+---------------+---------------+---------------+----------------+
| test/size | 128 x 100000 | 256 x 100000 | 512 x 100000 | 1024 x 100000 | 2048 x 100000 | 4096 x 100000 |
+------------+--------------+--------------+---------------+---------------+---------------+----------------+
| pipe | 153MB/s | 285MB/s | 515MB/s | 913MB/s | 1670MB/s | 2287MB/s |
| fifo | 144MB/s | 264MB/s | 481MB/s | 877MB/s | 1566MB/s | 2343MB/s |
| socketpair | 155MB/s | 290MB/s | 586MB/s | 1014MB/s | 1843MB/s | 2566MB/s |
| uds | 136MB/s | 267MB/s | 564MB/s | 920MB/s | 1704MB/s | 2626MB/s |
| tcp | 249MB/s | 339MB/s | 760MB/s | 1373MB/s | 1971MB/s | 2815MB/s |
| shm | 3.514287MB/s | 7.406006MB/s | 14.468472MB/s | 28.211735MB/s | 54.214965MB/s | 109.995927MB/s |
+------------+--------------+--------------+---------------+---------------+---------------+----------------+
fifo和pipe也差不多,第1台虚拟机不知道什么原因导致性能上的差距,我用/bin/time
分别调用了fifo和pipe发现:
# pipe
Percent of CPU this job got: 83%
Voluntary context switches: 63
Involuntary context switches: 1477
...
# fifo
Percent of CPU this job got: 48%
Voluntary context switches: 306
Involuntary context switches: 55582
...
fifo的CPU利用率并不高,时间都耗在强制的进程切换上了,至于为什么会有这么多的进程切换,我没有想明白。
但从其他两台机器的结果看,fifo和pipe是差不多的,而TCP一直都表现得很好。
另外关于共享内存的高性能测试,请看这个文章:
co lin:进程间通讯:RingBuffer的性能测试zhuanlan.zhihu.com