【一】进程间通信介绍
什么是进程间通信
-
进程间通信(Inter-process Communication,IPC)是指在不同进程之间传输数据或信号的机制。由于每个进程拥有自己独立的内存空间,所以不同进程之间无法直接访问对方的变量或数据结构。因此,操作系统提供了多种IPC机制来允许进程之间共享信息和协调操作。
-
通俗地理解,可以把进程间通信比作不同办公室之间的沟通。每个办公室(进程)有自己的空间和工作内容,但有时候它们需要交换信息或协调某些行动,这就需要特定的沟通方式(IPC机制)。
常见的IPC机制
- 管道(Pipes):
- 最基本的IPC机制之一。
- 类似于一根管道,一个进程在管道的一端输入数据,另一个进程从另一端读取数据。
- 管道通常是单向的,为了双向通信,需要两个管道。
- 消息队列(Message Queues):
- 允许不同进程发送和接收消息。
- 每个消息都是存储在队列中的数据块,进程可以读写这些消息。
【二】队列介绍
创建队列对象的类(底层就是以管道加锁来实现)
语法:
# 语法
import queue
q = queue.Queue(maxsize)
主要方法:
q.put
- 用以插入数据到队列中,put方法还有两个可选参数:blocked和timeout。
- 如果blocked为True(默认值),并且timeout为正值,该方法会阻塞timeout指定的时间,直到该队列有剩余的空间。如果超时,会抛出Queue.Full异常
- 如果blocked为False,但该Queue已满,会立即抛出Queue.Full异常。
q.get
- 可以从队列读取并且删除一个元素,同样,get方法有两个可选参数:blocked和timeout。
- 如果blocked为True(默认值),并且timeout为正值,那么在等待时间内没有取到任何元素,会抛出Queue.Empty异常。
- 如果blocked为False,有两种情况存在,如果Queue有一个值可用,则立即返回该值,否则,如果队列为空,则立即抛出Queue.Empty异常.
q.get_nowait()
- 同q.get(False)
q.put_nowait()
- 同q.put(False)
q.empty()
- 调用此方法时q为空则返回True,该结果不可靠,比如在返回True的过程中,如果队列中又加入了项目。
q.full()
- 调用此方法时q已满则返回True,该结果不可靠,比如在返回True的过程中,如果队列中的项目被取走。
q.qsize()
- 返回队列中目前项目的正确数量,结果也不可靠,理由同q.empty()和q.full()一样
【三】实现进程间通信
模板
from multiprocessing import Process, JoinableQueue
import time
import random
def producer(q, name, food):
for i in range(1, 8):
time.sleep(random.randint(1, 2))
q.put(food)
print(f'厨师{name}做了{food}')
def consumer(q, name):
while True:
food = q.get()
time.sleep(random.randint(1, 2))
print(f'顾客{name}吃完了{food}')
q.task_done()
if __name__ == '__main__':
q = JoinableQueue()
p1 = Process(target=producer, args=(q, '德华', '鸡蛋炒河粉'))
p2 = Process(target=producer, args=(q, '大仙', '大肉面条'))
c1 = Process(target=consumer, args=(q, 'hqq'), daemon=True)
c2 = Process(target=consumer, args=(q, 'green'), daemon=True)
p1.start()
p2.start()
c1.start()
c2.start()
p1.join()
p2.join()
q.join()
- 这个模板就是以厨师做饭和顾客吃饭为例子
- 厨师可以做饭(产生数据)----->放到餐桌(加入到队列)
- 顾客可以在餐桌(队列)----->吃饭(拿到数据)
【四】JoinableQueue类
- 我的理解是和Queue模块大体不差
- 用JoinableQueue类示例出来的对象,在每次put或者get都会对管道的数据数量进行计数
- 当task_done()执行后就会告诉告诉队列他已经从队列里面拿走了一个数据,并且已经处理完了
- 主进程最后的q.join()就是等待队列中所有的数据被取完,然后再继续往后执行