1. 必要性: 进程间空间独立,资源不共享,此时在需要进程间数据传输时就需要特定的手段进行数据通信。
2. 常用进程间通信方法
管道 消息队列 共享内存 信号 信号量 套接字
1. 通信原理
在内存中开辟管道空间,生成管道操作对象,多个进程使用同一个管道对象进行读写即可实现通信
2. 实现方法
from multiprocessing import Pipe
fd1,fd2 = Pipe(duplex = True)
功能: 创建管道
参数:默认表示双向管道
如果为False 表示单向管道
返回值:表示管道两端的读写对象
如果是双向管道均可读写
如果是单向管道fd1只读 fd2只写
fd.recv()
功能 : 从管道获取内容
返回值:获取到的数据
fd.send(data)
功能: 向管道写入内容
参数: 要写入的数据
示例:
# 管道通信
import os
import time
from multiprocessing import Pipe, Process
def fun(fd, name):
time.sleep(2)
fd.send({name: os.getpid()})
if __name__ == '__main__':
# 创建双向管道
fd1, fd2 = Pipe(duplex=True)
jobs = []
# 生成三个进程给管道写入信息
for i in range(3):
p = Process(target=fun, args=(fd1, i))
jobs.append(p)
p.start()
# 从管道中读取数据
for i in range(3):
data = fd2.recv()
print(data)
for i in jobs:
i.join()
1.通信原理
在内存中建立队列模型,进程通过队列将消息存入,或者从队列取出完成进程间通信。
2. 实现方法
from multiprocessing import Queue
q = Queue(maxsize=0)
功能: 创建队列对象
参数:最多存放消息个数
返回值:队列对象
q.put(data,[block,timeout])
功能:向队列存入消息
参数:data 要存入的内容
block 设置是否阻塞 False为非阻塞,默认为True,阻塞
timeout 超时检测
q.get([block,timeout])
功能:从队列取出消息
参数:block 设置是否阻塞 False为非阻塞
timeout 超时检测
返回值: 返回获取到的内容
q.full()
判断队列是否为满
q.empty()
判断队列是否为空
q.qsize()
获取队列中消息个数
q.close()
关闭队列
示例:
# 消息队列通信
from multiprocessing import Queue, Process
from time import sleep
from random import randint
def request(q):
for i in range(20):
x = randint(0, 100)
y = randint(0, 100)
# 默认为阻塞,当管道数据满时,会一直等待别的线程取走数据才会存入新数据
# 如果设置非阻塞,当管道数据满时会抛出异常:exception Queue.Full
q.put((x, y))
def handle(q):
while True:
sleep(0.5)
try:
# 默认为阻塞,当管道数据为空时,会一直等待别的线程写入数据才会取出新数据
# 如果设置非阻塞,当管道数据为空时会抛出异常:exception Queue.Empty
x, y = q.get(timeout=3) # 最多等待3秒,超时会抛异常
except:
break
else:
print("%d + %d = %d" % (x, y, (x + y)))
if __name__ == '__main__':
# 创建队列对象,可存放三个数据
q = Queue(3)
# 创建一个进程把数据存入队列(20个元组)
p1 = Process(target=request, args=(q,))
# 创建一个进程从队列中取值
p2 = Process(target=handle, args=(q,))
p1.start()
p2.start()
p1.join()
p2.join()
1. 通信原理:
在内中开辟一块空间,进程可以写入内容和读取内容完成通信,但是每次写入内容会覆盖之前内容。
2. 实现方法
数据类型
from multiprocessing import Value,Array
obj = Value(ctype,data)
功能 : 开辟共享内存
参数 : ctype 表示共享内存空间类型 'i' 'f' 'c'
data 共享内存空间初始数据
返回值:共享内存对象
obj.value 对该属性的修改查看即对共享内存读写
obj = Array(ctype,data)
功能: 开辟共享内存空间
参数: ctype 表示共享内存数据类型
data 整数则表示开辟空间的大小,其他数据类型表示开辟空间存放的初始化数据
返回值:共享内存对象
Array共享内存读写: 通过遍历obj可以得到每个值,直接可以通过索引序号修改任意值。
* 可以使用obj.value直接打印共享内存中的字节串
示例1:Value
from multiprocessing import Process, Value
import time
import random
# 操作共享内存
def man(money):
for i in range(30):
time.sleep(0.2)
money.value += random.randint(1, 1000)
def girl(money):
for i in range(30):
time.sleep(0.15)
money.value -= random.randint(100, 800)
if __name__ == '__main__':
# 创建共享内存数据
money = Value('i', 5000)
# 两个线程共同影响共享内存
p1 = Process(target=man, args=(money,))
p2 = Process(target=girl, args=(money,))
p1.start()
p2.start()
p1.join()
p2.join()
print("剩余:", money.value)
示例2:Array
from multiprocessing import Process, Array
# 创建共享内存
# 共享内存开辟5个整型列表空间
# shm = Array('i', 5) 参数2整数代表空间大小
def fun(shm):
# 共享内存对象可迭代
for c in shm:
print(c)
# 修改内存空间数据
shm[1] = b'o'
if __name__ == '__main__':
# shm = Array('i', [1, 2, 3]) 参数2直接传入数据
shm = Array('c', b'hello')
p1 = Process(target=fun, args=(shm,))
p1.start()
p1.join()
# 迭代取值
for i in shm:
print(i)
# 一次性取值
print(shm.value)
1. 通信原理
给定一个数量的信号对多个进程可见。多个进程都可以操作该信号量增减,并根据数量值决定自己的行为。
2. 实现方法
from multiprocessing import Semaphore
sem = Semaphore(num)
功能 : 创建信号量对象
参数 : 信号量的初始值
返回值 : 信号量对象
sem.acquire()
将信号量减1 当信号量为0时阻塞
sem.release()
将信号量加1
sem.get_value()
获取信号量数量
示例:
"""
信号量演示
注意: 信号量相当于资源,多个进程对数量进行控制
"""
from multiprocessing import Process, Semaphore
from time import sleep
import os
# 任务函数
def handle(s):
print("现存信号:", s.get_value())
s.acquire() # 执行任务必须消耗一个信号量
print("开始执行任务:", os.getpid())
sleep(2)
print("执行任务结束:", os.getpid())
s.release() # 增加一个信号量
if __name__ == '__main__':
# 创建信号量
sem = Semaphore(3)
# 创建5个线程,三个信号肯定不够,前三个线程将信号量兼为0,
# 后两个线程执行acquire时会鱼洞阻塞,
# 等待前三个中有人将信号还回才可以继续执行
for i in range(5):
p = Process(target=handle, args=(sem,))
p.start()