Python 多进程
多进程创建方式
Python 中使用 multiprocessing 模块来处理多进程。
-
直接创建 Process 对象
# -*- coding:utf-8 -*- from multiprocessing import Process import os, time def fun(i): print(f"I'm in {os.getpid()}, id is {i}, parent pid is{os.getppid()}") time.sleep(1) if __name__ == '__main__': #target 是子进程实际执行的方法, ags 是其参数。 processes = [Process(target=fun, args=(i,)) for i in range(3)] for p in processes: p.start() for p in processes: p.join() print(f"main pid: {os.getpid()} is finished")
-
通过 Pool 批量创建多进程
# -*- coding:utf-8 -*- from multiprocessing import Pool from time import ctime, sleep def loop(nloop, nsec): print("start loop", nloop, "at:", ctime()) sleep(nsec) print("loop", nloop, "done at:", ctime()) if __name__ == "__main__": pool = Pool(processes=3) for i in range(5): # 维持执行的进程总数为processes,当一个进程执行完毕后会添加新的进程进去 pool.apply_async(loop, args=(i, 5 - i)) print('====== apply_async ======') pool.close() # 调用join之前,先调用close函数,否则会出错。执行完close后不会有新的进程加入到pool,join函数等待所有子进程结束 pool.join()
多进程如何进行数据交互?
多进程之前通过 Queue 或 Pipe 进行通信,使用方式如下:
-
Queue: 队列,注意 Queue 只能子父进程共享。 如果用 Pool 方式创建的子进程需要用 Manager 来管理 Queue
Queue 是多进程多线程安全的。
# coding=utf-8 """ 模拟多个生产者和多个消费者的情况 """ from multiprocessing import Queue, Pool, Manager from os import getpid from time import sleep def producer(q: Queue): pid = getpid() print(f"pid: {pid} producing messages") for i in range(3): q.put(f"{i} : {pid}") sleep(1) def consumer(q: Queue): pid = getpid() for i in range(2): print(f"pid: {pid} consumed messages: {q.get()}") sleep(3) if __name__ == '__main__': manager = Manager() q = manager.Queue() pool = Pool(processes=5) for i in range(2): pool.apply_async(func=producer, args=(q,)) for j in range(3): pool.apply_async(func=consumer, args=(q,)) pool.close() pool.join()
-
Pipe 管道:双向通信。 跟队列不同的是, 队列只能一个进程写一个进程读。如果两个线程同时读写,自己会读取到自己写的东西,这就不是通信了。Pipe 可以双向通信,不过如果多个线程同时读或者同时写管道的同一端可能会导致数据损坏。
# coding=utf-8 """ 测试管道,实现连个进程之间对话 """ import os from multiprocessing import Pipe, Process from multiprocessing.connection import Connection def fun1(p: Connection): p.send(f"Hi i'm in {os.getpid()}") print(p.recv()) p.send(f"I received your message") p.close() def fun2(p: Connection): print(p.recv()) p.send(f"Hi ,hhh, {os.getpid()}") print(p.recv()) p.close() if __name__ == '__main__': parent_conn, child_conn = Pipe() p1 = Process(target=fun1, args=(parent_conn,)) c1 = Process(target=fun2, args=(child_conn,)) p1.start() c1.start() p1.join() c1.join()