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的复杂数据类型,必须在创建或修改的时候一次性赋值。
在创建之后的修改提交是不起作用的,详见上面的示例程序