python 多进程 每个进程做不同功能实例_python多进程通信实例分析
操作系统会为每一个创建的进程分配一个独立的地址空间,不同进程的地址空间是完全隔离的,因此如果不加其他的措施,他们完全感觉不到彼此的存在。那么进程之间怎么进行通信?他们之间的关联是怎样的?实现原理是什么?本文就来借助Python简单的聊一下进程之间的通信?还是那句话,原理是相同的,希望能透过具体的例子来体会一下本质的东西。
下面尽量以简单的方式介绍一下每一类通信方式,具体的细节可以参照文档使用;
1. 管道
先来看一下最简单、古老的一种IPC:管道。通常指的是无名管道,本质上可以看做一种文件,只存在于内存当中,不会存盘。不同进程通过系统提供的接口来向管道中读取或者写入数据。
也就是说我们通过这样一个中间介质为进程提供交流的方式。无名管道的局限在于一般只用于有直接关联关系的父子进程。下面通过一个简单的例子来看一下其用法。
from multiprocessing importProcess, Pipedefpstart(pname, conn):
conn.send("")print(conn.recv()) #if __name__ == ‘__main__‘:
conn1, conn2=Pipe(True)
sub_proc= Process(target=pstart, args=(‘subprocess‘, conn2,))
sub_proc.start()print (conn1.recv()) #"")
sub_proc.join()
管道通信三步曲:
创建Pipe,得到两个connection对象conn1和conn2;
父进程持有conn1,将conn2传递给子进程;
父子进程通过对持有的connection对象进行send和recv操作以进行数据传递和接受;
上面我们创建的是全双工管道,也可以创建半双工管道,具体使用可以参照官网描述:
Returns a pair (conn1, conn2) of Connection objects representing the ends of a pipe.
If duplex is True (the default) then the pipe is bidirectional. If duplex is False then the pipe is unidirectional: conn1 can only be used for receiving messages and conn2 can only be used for sending messages.
2. 具名管道(FIFO)
上面介绍的管道主要用于有直接关系的进程,局限性比较大。下面来看一下可以在任意进程间进行通信的具名管道。
由于window平台上os模块没有mkfifo属性,因此这个例子只能在linux上运行(测试环境 CentOS 7, Python 2.7.5):
#!/usr/bin/python
importos, timefrom multiprocessing importProcess
input_pipe= "./pipe.in"output_pipe= "./pipe.out"
defconsumer():ifos.path.exists(input_pipe):
os.remove(input_pipe)ifos.path.exists(output_pipe):
os.remove(output_pipe)
os.mkfifo(output_pipe)
os.mkfifo(input_pipe)
in1= os.open(input_pipe, os.O_RDONLY) #read from pipe.in
out1 = os.open(output_pipe, os.O_SYNC | os.O_CREAT |os.O_RDWR)whileTrue:
read_data= os.read(in1, 1024)print("received data from pipe.in: %s @consumer" %read_data)if len(read_data) ==0:
time.sleep(1)continue
if "exit" inread_data:breakos.write(out1, read_data)
os.close(in1)
os.close(out1)defproducer():
in2=None
out2= os.open(input_pipe, os.O_SYNC | os.O_CREAT |os.O_RDWR)for i in range(1, 4):
msg= "msg" +str(i)
len_send=os.write(out2, msg)print("------product msg: %s by producer------" %msg)if in2 isNone:
in2= os.open(output_pipe, os.O_RDONLY) #read from pipe.out
data = os.read(in2, 1024)if len(data) ==0:break
print("received data from pipe.out: %s @producer" %data)
time.sleep(1)
os.write(out2,‘exit‘)
os.close(in2)
os.close(out2)if __name__ == ‘__main__‘:
pconsumer= Process(target=consumer, args=())
pproducer= Process(target=producer, args=())
pconsumer.start()
time.sleep(0.5)
pproducer.start()
pconsumer.join()
pproducer.join()
运行流程如下:
每一轮的过程如下:
producer进程往pipe.in文件中写入消息数据;
consumer进程从pipe.in文件中读入消息数据;
consumer进程往pipe.out文件中写入回执消息数据;
producer进程从pipe.out文件中读出回执消息数据;
结果如下:
[[email protected] python]$ python main.py------product msg: msg 1 by producer------received datafrom pipe.in: msg 1@consumer
received datafrom pipe.out: msg 1@producer------product msg: msg 2 by producer------received datafrom pipe.in: msg 2@consumer
received datafrom pipe.out: msg 2@producer------product msg: msg 3 by producer------received datafrom pipe.in: msg 3@consumer
received datafrom pipe.out: msg 3@producer
received datafrom pipe.in: exit @consumer
View Code
两个进程没有直接的关系,每个进程有一个读文件和写文件,如果两个进程的读写文件是关联的,就可以进行通信。
3. 消息队列(Queue)
进程之间通过向队列中添加数据或者从队列中获取数据来进行消息数据的传递。下面是一个简单的例子。
from multiprocessing importProcess, Queueimporttimedefproducer(que):for product in (‘Orange‘, ‘Apple‘, ‘‘):print(‘put product: %s to queue‘ %product)
que.put(product)
time.sleep(0.5)
res=que.get()print(‘consumer result: %s‘ %res)defconsumer(que):whileTrue:
product=que.get()print(‘get product:%s from queue‘ %product)
que.put(‘suc!‘)
time.sleep(0.5)if notproduct:break
if __name__ == ‘__main__‘:
que= Queue(1)
p= Process(target=producer, args=(que,))
c= Process(target=consumer, args=(que,))
p.start()
c.start()
p.join()
c.join()
这个例子比较简单,queue的具体用法可以参考一下官网。
结果:
put product: Orange to queue
consumer result: suc!
put product: Apple to queue
consumer result: suc!
put product: to queue
consumer result: suc!
get product:Orangefromqueue
get product:Applefromqueue
get product:from queue
View Code
这里有几点需要注意下:
可以指定队列的容量,如果超出容量会有异常:raise Full;
默认put和get均会阻塞当前进程;
如果put没有设置成阻塞,那么可能自己从队列中取出自己放入的数据;
4. 共享内存
共享内存是一种常用的,高效的进程之间的通信方式,为了保证共享内存的有序访问,需要对进程采取额外的同步措施。
下面的这个例子仅仅简单的演示了Python中如何在不同进程间使用共享内存进行通信的。
from multiprocessing importProcessimportmmapimportcontextlibimporttimedefwriter():
with contextlib.closing(mmap.mmap(-1, 1024, tagname=‘cnblogs‘, access=mmap.ACCESS_WRITE)) as mem:for share_data in ("Hello", "Alpha_Panda"):
mem.seek(0)print(‘Write data:== %s == to share memory!‘ %share_data)
mem.write(str.encode(share_data))
mem.flush()
time.sleep(0.5)defreader():whileTrue:
invalid_byte, empty_byte= str.encode(‘\x00‘), str.encode(‘‘)
with contextlib.closing(mmap.mmap(-1, 1024, tagname=‘cnblogs‘, access=mmap.ACCESS_READ)) as mem:
share_data= mem.read(1024).replace(invalid_byte, empty_byte)if notshare_data:"""当共享内存没有有效数据时结束reader"""
break
print("Get data:== %s == from share memory!" %share_data.decode())
time.sleep(0.5)if __name__ == ‘__main__‘:
p_reader= Process(target=reader, args=())
p_writer= Process(target=writer, args=())
p_writer.start()
p_reader.start()
p_writer.join()
p_reader.join()
执行结果:
Write data:== Hello ==to share memory!
Write data:== Alpha_Panda ==to share memory!
Get data:== Hello == fromshare memory!
Get data:== Alpha_Panda == from share memory!
下面简单的来说明一下共享内存的原理;
进程虚拟地址到物理地址的一个映射关如下:
上面这个图已经很明白的展示了共享内存的原理。
左边是正常情况下,不同进程的线性地址空间被映射到不同的物理内存页,这样不管其他进程怎么修改物理内存,都不会影响到其他进程;
右边表示的是进程共享内存的情况下,不同进程的部分线性地址会被映射到同一物理页,一个进程对这个物理页的修改,会对另一个进程立即可见;
当然潜在的问题就是要采取进程同步措施,也就是对共享内存的访问必须是互斥的。这个可以借助信号量来实现。
5. socket通信
最后再来介绍一种可以跨主机的进程间通信:socket。
懂网络编程的人,对这个应该都比较熟悉。socket不仅可以跨主机进行通信,甚至有时候可以使用socket在同一主机的不同进程间进行通信。
这部分代码比较简单常见,这里仅仅使用流程图来表示一下socket通信的流程及相关接口。
上图表示客户端上某进程使用socket和服务器上监听程序进行socket通信的一个流程。
小结
到这里关于常见的进程间通信相关的概念和实例均简单介绍了一下。希望本文能让你对进程间通信有一个更深入的理解和认识。
结合之前几篇介绍线程、进程概念及线程间同步的一些措施的介绍,相信应该对线程和进程相关概念有一个简单清晰的认识了。
原文:https://www.cnblogs.com/yssjun/p/11438850.html
python 多进程 每个进程做不同功能实例_python多进程通信实例分析相关推荐
- python 多进程 每个进程做不同功能实例_Python 多进程并发操作中进程池Pool的实例...
{"moduleinfo":{"card_count":[{"count_phone":1,"count":1}],&q ...
- python 类 实例_Python类的实例详解
类(class)是一个用户自定义类型,开发者可以将其实例化以获得实例(instance),实例表示这种类型的对象.在Python中,类就是对象,开发者可以像对其他对象那样处理函数,可以在调用函数时传递 ...
- python多进程编程实例_Python多进程编程multiprocessing代码实例
下面记录一下多进程编程的别一种方式,即使用multiprocessing编程 import multiprocessing import time def get_html(n): time.slee ...
- python可以做数据库功能吗_python可以用哪些数据库
早期数据库模型有三种,分别为层次式数据库.网络式数据库和关系型数据库. 而在当今的互联网中,通常把数据库分为两类,即关系型数据库和非关系型数据库. 关系型数据库 关系型数据库是指采用了关系模型来组织数 ...
- python可以做数据库功能吗_Python折腾数据库(一)peewee
SQL数据库恐怕没几个人能够绕过去,自己折腾跑分析也有几个年头了回头想想之前就是吃了没有充分利用数据库来管理数据的亏. 二的话,有缘再见,最近想学一下SQLAlchemy 先推荐两个数据库的图形化查看 ...
- python字符串处理编程实例_Python字符串处理实例详解
干货大礼包!21天带你轻松学Python(文末领取更多福利) 点击查看课程视频地址 本课程来自于千锋教育在阿里云开发者社区学习中心上线课程<Python入门2020最新大课>,主讲人姜伟. ...
- python数据库管理实例_Python数据库连接池实例——PooledDB
不用连接池的MySQL连接方法 import MySQLdb conn= MySQLdb.connect(host='localhost',user='root',passwd='pwd',db='m ...
- python scrapy教程实例_Python之scrapy实例1
下文参考:http://www.jb51.net/article/57183.htm 个人也是稍加整理,修改其中的一些错误,这些错误与scrapy版本选择有关,个环境:Win7x64_SP1 + Py ...
- python django实例_python django 模板实例
操作系统MAC OS/LINUX windows 安装python3 版本3自带virtualenv 安装virtualenv: pip install virtualenv 创建虚拟环境 virtu ...
最新文章
- 【翻译】Programming Ruby——数组,哈希表和控制结构
- flutter 应用场景_【Flutter 1-12】Flutter手把手教程Dart语言——什么是泛型和泛型的使用场景...
- 温州大学《深度学习》课程课件(一)
- MapReduce:Simplified Data Processing on Large Clusters中文版from百度文库
- DCMTK:转换dicom文件编码
- RxDownload2 文件下载太慢分析
- C语言实现单链表操作
- readfile函数使用方法_1分钟学会LOOKUP函数,有网友说使用这个方法,初学者秒变大神...
- mysql 准则 杂谈
- 光伏组件市场价格战下谁获益?
- mac win7 计算机,详解mac如何安装win7
- c++5.8.2免费 dev_devc 中文版下载
- 算法图解第四章笔记与习题(快速排序)
- 中国工业互联网相关政策汇总分析:“十四五”系列规划助力工业互联网创新融合发展[图]
- 悦虎洛达1562M二代固件升级包最新V1.40更新日期2021.1.12(教程)
- 邮件服务器没有MX类型,mx记录和邮件服务器的关系究竟是什么?
- UnixBench测试服务器性能
- 【BUG】Ubuntu 3090显卡驱动掉了,重新安装
- 含泪整理最优质现代家装su模型素材,你想要的这里都有
- (4)AES分组加密算法(原理详解)
热门文章
- Linux下可以替代windows的软件汇总:(不断完善中)
- android oppo支付宝,安卓首家 OPPO联合支付宝开启3D人脸支付技术
- 怎么以管理员身份运行cmd?以管理员身份运行cmd方法介绍
- windows如何以管理员身份运行cmd
- 黑苹果A卡用户升级到Catalina 10.15.1版本后出现黑屏的解决方案
- Sqlite数据库加密方法
- 导航上显示某个地点已关闭什么意思_苹果手机中这4个功能最好立马关闭,不然手机耗电特别快...
- Linux那些事儿之我是Hub(19)八大重量级函数闪亮登场(三)
- java实现等腰三角形
- markdown文件表格的写法