Python中的多线程实际上是伪多线程,无法利用多核CPU的并列运算优势,所以Python多线程适合用在IO密集型的程序中。
而cpu运算密集型的程序的并发应该使用多进程。
多进程之间的数据交互主要有Queue、Pipe和Manager,其中队列Queue和管道Pipe只能应用于相同主进程创建出来的进程间的数据交换,
Manager则是可以应用于无关的两个进程间进行数据共享。
Queue
进程Queue与线程queue用法基本相同,但是Queue必须作为子进程的传入参数,否则因为不同进程内存独立的缘故是无法访问主进程中定义的Queue的。
import time import multiprocessing from multiprocessing import Queue from multiprocessing import Lock pq = Queue() """ 注意多进程Queue必须作为参数传递给子进程,否则子进程是无法获取父进程中的变量的 多进程Queue的实质是将Queue拷贝到各个进程之中,任何一个进程做出修改都会同步到其他进程的拷贝上 """ def pqGet(pq,lock): while True: item = pq.get() pq.put("a") #进程锁,防止屏幕输出混乱 lock.acquire() print(item) lock.release() time.sleep(1) if __name__ == "__main__": #注意锁必须作为传入参数 lock = Lock() for i in range(100): pq.put(i) for i in range(5): p = multiprocessing.Process(target = pqGet,args=(pq,lock,)) p.start()
Pipe
管道Pipe一般用于两个进程间的数据交互。管道两端会自动进入阻塞状态。
import multiprocessing from multiprocessing import Pipe def func(conn): print(conn.recv()) conn.send([1,2,3,"asd"]) if __name__ == "__main__": connFrom, connTo = Pipe() connFrom.send("hello") p = multiprocessing.Process(target=func,args=(connTo,)) p.start() print(connFrom.recv())
Manager
Manager是一种高级的进程间数据共享的方法,支持Python所有的数据结构。
与Queue和Pipe不同,Manager并不限定必须是同一父进程创建的进程间数据交换。
Manager的本质是启动一个ManagerSever进程监听socket其它进程通过socker连接ManagerServer实现通信
from multiprocessing import Process, Manager import multiprocessing,time def func(lst,index): print("[%d]first:" %index,lst) lst.append(100) print("[%d]second:" %index,lst) time.sleep(1) if __name__ == '__main__': mng = Manager() lst = mng.list([1,2,3,4,5]) """ 对于manager的复杂数据类型,必须在创建的时候一次性赋值 在创建之后的修改提交是不起作用的,所以下面第二第三条赋值语句是无效的 """ lst[1] = list([1, 2]) lst[1].append(0.1)#err lst[1][1] = "hello"#err plst = [] for i in range(2): p = multiprocessing.Process(target=func,args=(lst,i,)) p.start() plst.append(p) for p in plst: p.join() print("main:",lst)
Manager有一个必须注意的点,
对于manager的复杂数据类型,必须在创建或修改的时候一次性赋值。
在创建之后的修改提交是不起作用的,详见上面的示例程序