Python进程间通信(Queue和Pipe)

1,314 阅读4分钟

one进程间通信

⚽ 使用Queue(队列)实现进程间通信

  • multiprocessing 模块中的 Queue 类可以实现进程间通信

  • Queue类方法介绍

    from multiprocessing import Queue
    Obj = Queue()
    
    • Obj.put(item, block=True, timeout=None) item添加队列; block当参数为true时,一旦队列被写满,则代码就会被阻塞,直到有进程取走数据并腾出空间给Obj使用; timeout参数用来设置阻塞的时间,即程序最多在阻塞timeout秒之后,如果还没有空间空闲,则程序会抛出queue.Full异常。

    • Obj.get(block=True, timeout=None) 从队列中删除并返回项目; 如果可选参数blocktruetimeoutNone(默认值),如有必要,请阻止,直到项目可用。

    • Obj.put_nowait(item) 在不阻塞的情况下将项目放入队列。仅当可用插槽立即可用时才将项目排队。否则将引发完全异常。

    • Obj.get_nowait() 在不阻塞的情况下从队列中移除并返回项目。只有在立即可用的情况下才能获取项目。否则引发空异常。

    • Obj.empty() 队列是否为空判断,如果为空,则该方法返回值True;反之,返回False

    eg:

    from multiprocessing import Process, Queue, current_process
    
    
    def processFun(queue, name):
       print(current_process().pid, "进程放数据:", name)
       # 将 name 放入队列
       queue.put(name)
    
    
    if __name__ == '__main__':
       # 创建进程通信的Queue
       queue = Queue()
       # 创建子进程
       process = Process(target=processFun, args=(queue, "sun process"))
       # 启动子进程
       process.start()
       # 该子进程必须先执行完毕
       process.join()
       print(current_process().pid, "取数据:")
       print(queue.get())
    

    result:

        5200 进程放数据: sun process
        15152 取数据:
        sun process
    

🏐 使用PIPE(管道)实现进程间通信

  • 使用Pipe实现进程通信,首先需要调用multiprocessingPipe()函数来创建一个管道。 eg:
conn1,conn2 = multiprocessing.Pipe(duplex=True)
  • conn1conn2分别用来接收Pipe函数返回的两个端口;duplex 参数默认为 True,表示该管道是双向的,即位于 2 个端口的进程既可以发送数据,也可以接受数据,而如果将 duplex 值设为 False,则表示管道是单向的,conn1 只能用来接收数据,而 conn2 只能用来发送数据。

  • conn.send()发送数据

  • conn.recv()接收发过来的数据

  • conn.close()关闭连接

  • conn.poll()返回连接中是否还有数据可以读取

  • conn.send_bytes(buf, offset=0, size=None) 发送字节数据。如果没有指定 offsetsize 参数,则默认发送 buffer 字节串的全部数据;如果指定了 offsetsize 参数,则只发送 buffer 字节串中从 offset 开始、长度为 size 的字节数据。通过该方法发送的数据,应该使用 recv_bytes()recv_bytes_into 方法接收。

  • conn.recv_bytes(maxlength) 接收通过 send_bytes() 方法发送的数据,maxlength 指定最多接收的字节数。该方法返回接收到的字节数据。

  • conn.recv_bytes_into(buf, offset=0) 功能与 recv_bytes() 方法类似,只是该方法将接收到的数据放在 buffer 中。

eg:

from multiprocessing import current_process, Pipe, Process


def processFun(conn, name):
    print(current_process().pid, "进程发送数据:", name)
    conn.send(name)
    # conn.send_bytes(bytes(name))


if __name__ == '__main__':
    # 创建管道
    conn1, conn2 = Pipe()
    # 创建子进程
    process = Process(target=processFun, args=(conn1, "Sun Pipe Process"))
    # 启动子进程
    process.start()
    process.join()

    print(current_process().pid, "接收数据:")
    print(conn2.recv())
    # print(conn2.recv_bytes())

result:

4440 进程发送数据: Sun Pipe Process
3816 接收数据:
Sun Pipe Process

two进程锁

  • ⚾ 使用Lock实现进程锁,首先需要调用multiprocessingLock来创建一个对象。使用Obj对象的acquire方法锁住进程。使用Objrelease方法释放锁。 eg:
from multiprocessing import Process, Lock


def f(Obj, i):
    Obj.acquire()  # 锁住进程
    try:
        print('hello world', i)
    finally:
        Obj.release()  # 释放锁


if __name__ == '__main__':
    Obj = Lock()
    for num in range(10):
        Process(target=f, args=(Obj, num)).start()

result:

hello world 6
hello world 4
hello world 7
hello world 3
hello world 2
hello world 1
hello world 8
hello world 9
hello world 5
hello world 0

three生产消费者模型

  • 🏀 创建producer(生产者)函数和customer(消费者)函数
def producer(q, role):
    print("start producer")
    for i in range(10):
        q.put(i)  # 生产者
        time.sleep(0.5)
        print(f"{role} has set value {i}")
    print("end producer")


def customer(q, role):
    print("start customer")
    while 1:
        data = q.get()  # 消费者
        print(f"{role} has get value {data}")
  • 🎳 创建一个队列,供生产消费者使用
Obj = Queue()
  • 🏑 将生产消费任务添加到Thread
pro = Thread(target=producer, args=(Obj, "生产者")).start()
cus = Thread(target=customer, args=(Obj, "消费者")).start()

eg:

from multiprocessing import Queue
from threading import Thread

import time


def producer(q, role):
    print("start producer")
    for i in range(10):
        q.put(i)  # 生产者
        time.sleep(0.5)
        print(f"{role} has set value {i}")
    print("end producer")


def customer(q, role):
    print("start customer")
    while 1:
        data = q.get()  # 消费者
        print(f"{role} has get value {data}")


if __name__ == '__main__':
    Obj = Queue()  # 创建一个队列
    pro = Thread(target=producer, args=(Obj, "生产者")).start()
    cus = Thread(target=customer, args=(Obj, "消费者")).start()

result:

start producer
start customer
消费者 has get value 0
生产者 has set value 0
消费者 has get value 1
生产者 has set value 1
消费者 has get value 2
生产者 has set value 2
消费者 has get value 3
生产者 has set value 3
消费者 has get value 4
生产者 has set value 4
消费者 has get value 5
生产者 has set value 5
消费者 has get value 6
生产者 has set value 6
消费者 has get value 7
生产者 has set value 7
消费者 has get value 8
生产者 has set value 8
消费者 has get value 9
生产者 has set value 9
end producer