进程间通信 -- 各种通信方式的一方天地
真是个好问题
今天突然被 ==“不同场景下该如何选择进程间通信方式?”==给噎着了,这我还真没认真想过,以前只知道说它们都是什么?为什么?怎么用?还真没想过什么时候用谁?这个问题。
管道
在shell中管道用“|”表示。管道的历史很悠久了。
可以理解为内存中的一个缓冲区,用于将某个进程的数据流导入,由某一个进程导出,实现通信。
这种管道是没有名字,所以「|」表示的管道称为匿名管道,用完了就销毁。
注意,这个匿名管道是特殊的文件,只存在于内存,不存于文件系统中。
匿名管道用于有血缘关系的进程间通信。
在 shell 里面执行 A | B命令的时候,A 进程和 B 进程都是 shell 创建出来的子进程,A 和 B 之间不存在父子关系,它俩的父进程都是 shell。
如果要用管道进行无血缘关系之间的进程通信,用FIFO有名管道。
局势到这里已经很清楚了,管道具有:“召之即来,挥之即去,且不占文件系统位置”的特性,适合用于shell中的“一次性博弈”。
如果是“长期博弈”,它不行,得往后看。
消息队列
相对于管道的种种限制,消息队列就显得明智多了,因为它存着“尾款”啊,所以在系统中存留的必要性就大了。
1、消息队列是内核地址空间中的内部链表,通过Linux内核在不同的进程间传递消息。
2、消息顺序的发送到消息队列中,并以几种不同的方式从队列中获取。
3、内核中的消息队列是通过IPC标识符来进行区别的,不同消息队列之间是互相独立的。
4、每个消息队列中的消息又构成一个独立的链表。
我把它看作一个“丰巢”。
但是吧,消息队列固然有它的局限性在:
消息队列不适合比较大数据的传输,因为在内核中每个消息体都有一个最大长度的限制,同时所有队列所包含的全部消息体的总长度也是有上限。在 Linux 内核中,会有两个宏定义 MSGMAX 和 MSGMNB,它们以字节为单位,分别定义了一条消息的最大长度和一个队列的最大长度。
消息队列还是很赞的,单看上面这些特性,比管道占地方,比后面要讲的SHM慢,传输消息大小也不如MMP,还异步,靠。
就是这么个“一无是处”的通信方式,硬生生把自己的劣势转化为了优势,不然它都不知道被压到哪个箱底去了。
对,就是异步。
随着“异步业务”的出现(如双十一流量削峰、秒杀系统等),消息队列突然就成了香饽饽,它能承载的消息比管道多,它也不追求速度,占用的内存还比MMP小,简直就是用来做流量削峰、解耦、异步的神器。
RobbieMQ、RocketMQ、Kafka。消息队列:解耦、异步、流量削峰。当下流行的几款MQ以及新手上路该如何选择MQ?
消息队列火了,命运也真是神奇啊。
内存共享映射(SHM)
1、共享内存是在多个进程之间共享内存区域的一种进程间的通信方式。
2、它是在多个进程间通过对指定内存段进行映射实现内存共享的。
3、这是IPC最快捷的方式,因为它没有中间商赚差价。
4、多个进程间共享的是同一块物理空间,仅仅是挂载地址不同而已,因此不需要进行复制,可以直接使用这段空间。
优点很明显了,快,承载数据量也够,一般用来进行进程间数据包通信(数据包不会太大,而且量多)。
但是如果要进行大文件操作,那这个就有点吃不消了,不是说不行,是扬短避长了哈哈哈,千里马非要它去拉磨。
文件内存映射(MMP)
1、mmap()函数用来将文件或者设备映射到内存中。
2、mmap的特点是按需调页。最开始只申请vma,并不调真正的页。当对某些页进行引用的时候,会引起一个缺页中断,再将页面调入到内存当中,这样避免了对内存的浪费。
mmap的优势: 操作文件就像操作内存一样,适合于对较大文件的读写。
mmap的缺点:
1、文件如果很小,比如60bytes,由于在内存当中的组织都是按页组织的,将文件调入到内存当中是一个页4k,这样其他的4096-60=4036 bytes的内存空间就会浪费掉了。
信号量
进程间通信的信号量其实我不是很想讲,现在高并发都是线程实现了,用进程去做高并发的话,emmm,浪费。
信号也不提了。。
网络流通信(Socket)
前面提到的管道、消息队列、共享内存都是在同一台主机上进行进程间通信,那要想跨网络与不同主机上的进程之间通信,就需要 Socket 通信了。
使用Socket通信也是分布式服务的一个大前提。
使用网络通信时需要在终端上开端口,占用网络资源等等,而且还要在网络上跑一圈再回来,所以,如果是同一台主机上就不用过多考虑这个了,它的天地在“分布式部署”上。
文章来源: lion-wu.blog.csdn.net,作者:看,未来,版权归原作者所有,如需转载,请联系作者。
原文链接:lion-wu.blog.csdn.net/article/details/107748046
- 点赞
- 收藏
- 关注作者
评论(0)