进程间通信
- 必要性:进程间空间独立,资源不共享,此时在需要进程间数据传输时就需要特定的手段进行数据通信。
- 常用进程间通信方法:管道 消息队列 共享内存 信号 信号量 套接字
1、管道通信(Pipe)
通信原理:在内存中开辟管道空间,生成管道操作对象,多个进程使用通一个管道对象读写即可实现通信。
实现方法:
from multiprocess import Pipe
fd1,fd2 = Pipe(duplex=True)
功能:创建管道
参数:默认表示双向管道
如果False,表示单向管道
返回值:表示管道两端的读写对象
如果是双向管道均可读写
如果是单向管道fd1只读,fd2只写
fd.recv()
功能:从管道获取内容
返回值:获取到的数据
fd.send(data)
功能:向管道写入内容
参数:要写入的数据
示例代码:process_pipe.py
#!/usr/bin/python3
"""
启动两个子进程,这两个子进程通过双向管道通信
"""
from multiprocess import Pipe, Process
fd1,fd2 = Pipe() # 创建双向通信管道
def app1():
print("app1 starts")
print("app1 writes to app2")
fd1.send('app1 data')
data = fd1.recv()
print('app1 receive data from app2:',data)
def app2():
print("app2 starts")
data = fd2.recv()
print('app2 receive data from app1:',data)
print('app2 send data to app1')
fd2.send('app2 data')
p1 = Process(target=app1) # 用单独进程运行app1函数
p2 = Process(target=app2) # 用单独进程运行app2函数
p1.start()
p2.start()
p1.join()
p2.join()
print('main process finished')
测试结果:
[root@gyl-huawei python]# vim process_pipe.py
[root@gyl-huawei python]# ./process_pipe.py
app2 starts
app1 starts
app1 writes to app2
app2 receive data from app1: app1 data
app2 send data to app1
app1 receive data from app2: app2 data
main process finished
消息队列:
通信原理:在内存中建立队列模型,进程通过队列将消息存入,或者从队列去除完成进程间通信。
实现方法:
from multiprocess import Queue
q = Queue(maxsize=0)
功能:创建队列对象
参数:最多存放消息个数
返回值:队列对象。
q.put(data,[block,timeout])
功能:向队列存入消息
参数:data 要存入的内容
block 设置是否阻塞,False是非阻塞
timeout 超时检测
q.get([block,timeout])
功能:从队列取出消息
参数 block设置是否阻塞 False为非阻塞
timeout 超时检测
返回值:返回获取到的内容
q.full() 判断队列是否为空
q.empty() 判断队列是否为空
q.qsize() 获取队列中消息个数
q.close() 关闭队列
示例代码: process_queue.py
#!/bin/env python3
from multiprocess import Process, Queue,Lock
from time import sleep
from random import randint
queue = Queue(5) # 队列中最多放5个元素
def producer(pid):
"""
生产者:
pid:标识生产者的号码
产生一个1~100之间的随机数放入队列,如果队列满了,则睡眠2秒
"""
flag = False
while True:
num = randint(1,100)
sleep(1)
lock.acquire()
if not queue.full():
queue.put(num)
print("producer %d put (%d) to queue " % (pid, num))
else:
flag = True
lock.release()
if flag == True:
flag = False
sleep(2)
def consumer(cid):
"""
从队列中取出一个数值,如果队列为空,则睡眠2秒
cid:标识消费者的号码
"""
flag = False
while True:
sleep(1.5)
lock.acquire()
if not queue.empty():
num = queue.get()
print("comsumer %d get (%d) from queue" % (cid, num))
else:
flag = True
lock.release()
if flag == True:
flag = False
sleep(2)
lock = Lock()
# 产生两个生产者,3个消费者
p1=Process(target=producer, args=(1,))
p2=Process(target=producer, args=(2,))
c1=Process(target=consumer, args=(1,))
c2=Process(target=consumer, args=(2,))
c3=Process(target=consumer, args=(3,))
go_on = True
tasks = [p1,p2,c1,c2,c3]
taskw = []
for task in tasks:
task.deamon=True
task.start()
taskw.append(task)
for task in taskw:
task.join()
print("main process completed")
测试结果:
[root@gyl-huawei python]# ./process_queue.py
producer 2 put (56) to queue
producer 1 put (27) to queue
comsumer 1 get (56) from queue
comsumer 2 get (27) from queue
producer 2 put (47) to queue
producer 1 put (64) to queue
producer 2 put (75) to queue
comsumer 1 get (47) from queue
producer 1 put (35) to queue
comsumer 2 get (64) from queue
producer 2 put (15) to queue
producer 1 put (84) to queue
comsumer 1 get (75) from queue
comsumer 2 get (35) from queue
producer 2 put (40) to queue
producer 1 put (38) to queue
comsumer 3 get (15) from queue
comsumer 1 get (84) from queue
producer 2 put (19) to queue
comsumer 2 get (40) from queue
producer 1 put (25) to queue
comsumer 3 get (38) from queue
^CProcess Process-4:
共享内存:
通信原理:在内存中开辟一块空间,进程可以写入内容和读取内容完成通信,但是每次内容会覆盖之前内容。
obj=Value(ctype, data)
功能:开辟共享内存
参数:ctype 表示共享内存空间类型 ‘i’ ‘f’ ‘c’ data 共享内存空间的初始数据
obj.value: 对该属性的修改查看即对共享内存读写
object = Array(ctype, data)
功能:开辟共享内存空间
参数:ctype 表示共享内存空间类型 data 整数则表示开辟空间的大小,其它数据类型表示开辟空间
返回值:共享内存对象。
Array共享内存读写:通过遍历obj可以得到每个值,直接可以通过索引获取
可以使用obj.value直接打印共享内存中的字节串。
代码示例:
#!/bin/env python3
"""
共享内存示例:一个进程每次产生五个随机整数存入数组共享内存,另一个进程通过数组共享内存每次获取5个随机数并显示在终端。一个值共享内存协调两个进程的运行。
"""
from multiprocess import Process, Value, Array
from time import sleep
from random import randint
shm_value = Value('i',0) # 值共享内存
shm_array= Array('i',5) # 数组共享内存
def producer(shm_value,shm_array):
while True:
if shm_value.value == 1:
sleep(1)
else:
vals = []
for i in range(5):
val = randint(1,100)
shm_array[i] = val
vals.append(val)
print('producer puts values completed:',vals)
shm_value.value = 1
def consumer(shm_value, shm_array):
while True:
if shm_value.value == 0:
sleep(1)
else:
vals = []
for i in range(5):
vals.append(shm_array[i])
print("consumer gets values:", vals)
shm_value.value = 0
p1 = Process(target=producer,args=(shm_value,shm_array))
c1 = Process(target=consumer,args=(shm_value,shm_array))
p1.daemon = True
c1.daemon = True
p1.start()
c1.start()
#
p1.join()
c1.join()
print("main process completed")
测试:producer进程一次产生5个随机数,comsumer一个取出5个随机数,两个进程交替工作
[root@gyl-huawei python]# ./process_shm.py
producer puts values completed: [71, 43, 97, 43, 59]
consumer gets values: [71, 43, 97, 43, 59]
producer puts values completed: [50, 14, 97, 62, 87]
consumer gets values: [50, 14, 97, 62, 87]
producer puts values completed: [36, 81, 30, 70, 3]
consumer gets values: [36, 81, 30, 70, 3]
producer puts values completed: [80, 89, 49, 89, 89]
consumer gets values: [80, 89, 49, 89, 89]
producer puts values completed: [36, 71, 79, 74, 17]
^CProcess Process-2:
信号量
通信原理:给定一个数量对多个进程可见。多个进程可以操作该数量增减,并根据数量值决定自己的行为。
实现方法:
from multiprocess import Semaphore
sem = Semaphore(num)
功能:创建信号量对象。
参数:信号量的初始值。
返回值:信号量对象。
sem.acquire() 信号量减1 当信号量为0时阻塞。
sem.release() 将信号量加1
sem.get_value() 获取信号量数量。
代码示例:
#!/bin/env python3
from multiprocess import Process, Semaphore
from time import sleep
def func(i,sem):
sem.acquire()
print("function %d starting" % i)
sleep(2)
print("function %d finished!" % i)
sem.release()
if __name__ == "__main__":
sem = Semaphore(3)
tasks = []
for i in range(12):
p = Process(target=func, args=(i+1,sem))
tasks.append(p)
p.deamon = True
p.start()
for task in tasks:
task.join()
测试:每个进程只能获取信号量后才能运行,最多只能3个进程一起运行。
[root@gyl-huawei python]# ./process_sem.py
function 5 starting
function 6 starting
function 2 starting
function 5 finished!
function 3 starting
function 6 finished!
function 7 starting
function 2 finished!
function 8 starting
function 3 finished!
function 7 finished!
function 8 finished!
function 9 starting
function 4 starting
function 1 starting
function 9 finished!
function 4 finished!
function 1 finished!
function 10 starting
function 11 starting
function 12 starting
function 10 finished!
function 11 finished!
function 12 finished!