Python并发编程基础 №④ 管道、数据共享、进程池(原理、效率测试、回调函数)
1、进程间数据传递之管道(Pipe)
1 conn1, conn2 = Pipe() 2 conn1.send('hello Pipe') 3 print(conn2.recv()) 4 conn1.close() 5 # print(conn2.recv()) # EOFError 6 conn2.close() 7 8 # demo2 9 def recv(conn): 10 while 1: 11 re = conn.recv() 12 if re: 13 print(re) 14 else: 15 break 16 conn.close() 17 18 if __name__ == '__main__': 19 conn1, conn2 = Pipe() 20 Process(target=recv, args=(conn2,)).start() 21 for i in range(3): 22 conn1.send('hello recv%d'%i ) 23 conn1.send(None) 24 conn1.close() 25 conn2.close() 26 27 # demo3 28 def get(conn1, conn2): 29 conn1.close() 30 31 while 1: 32 try: 33 print('========', conn2.recv()) 34 except EOFError: 35 conn2.close() 36 break 37 38 if __name__ == "__main__": 39 conn1, conn2 = Pipe() 40 Process(target=get, args=(conn1, conn2)).start() 41 conn2.close() 42 for i in range(5): 43 conn1.send('hello main') 44 conn1.close()
2、进程间的数据共享 Manager
1 from multiprocessing import Manager 2 from multiprocessing import Process 3 4 5 def add(dic): 6 print(dic['count']) # 子进程中可以使用 7 dic['count'] += 1 8 9 10 if __name__ == '__main__': 11 12 manager = Manager() 13 dic = manager.dict({'count': 100}) # 主进程定义的dict 14 # dic.setdefault('name', 'tom') # todo 不能如此增加字典中的项 15 16 p_lst = [] 17 for i in range(10): 18 p = Process(target=add, args=(dic, )) 19 p.start() 20 p_lst.append(p) 21 [p.join() for p in p_lst] 22 print(dic) 23 # p.join() # 没有join会报错:FileNotFoundError: [WinError 2] 系统找不到指定的文件。
3、用管道来实现生产者和消费者问题
1 import time, random 2 from multiprocessing import Process 3 from multiprocessing import Pipe 4 5 6 def produce(conn1, conn2): 7 conn2.close() 8 for i in range(10): 9 time.sleep(random.random()) 10 msg = '\33[32m新闻社刚刚生成了一条消息,编号No:%d\33[0m' % i 11 print(msg) 12 conn1.send(msg) 13 conn1.close() 14 15 16 def consume(conn): 17 while 1: 18 try: 19 print('消费者消费了:', conn.recv()) 20 except EOFError: 21 conn.close() 22 break 23 24 25 if __name__ == '__main__': 26 conn1, conn2 = Pipe() 27 28 p1 = Process(target=produce, args=(conn1, conn2)) 29 p1.start() 30 conn1.close() 31 32 c = Process(target=consume, args=(conn2,)) 33 time.sleep(random.randint(1,2)) 34 c.start() 35 36 conn2.close()
4、进程池
(1)原理
为什么会有进程池的概念
效率
每开启进程,开启属于这个进程的内存空间
寄存器 堆栈 文件
进程过多 操作系统的调度
进程池
python中的 先创建一个属于进程的池子
这个池子指定能存放n个进程
先将这些进程创建好
(2)demo与进程池效率测试
1 from multiprocessing import Pool, Process 2 3 # demo1: 4 def func(x): 5 time.sleep(random.random()) 6 print('hello ***') 7 print('-'*46) 8 9 10 if __name__ == '__main__': 11 pool = Pool(7) # 此处可不设,设的话就设你的cpu核数加1,即一次起7个进程 12 pool.map(func, range(21))

1 # demo2 map方法 2 # 与传统的Process比较,Pool明显效率更高! 3 def func(n): 4 for i in range(10): 5 print(n+1) 6 7 def func2(n): 8 for i in range(10): 9 print(n+2) 10 11 if __name__ == '__main__': 12 start = time.time() 13 pool = Pool(7) # 7个进程 14 pool.map(func, range(100)) # 100个任务 15 #pool.map(func2, [('tom', 1), 'jack']) # map的传多个参数 16 17 t1 = time.time() - start # 耗时 0.26628756523132324 18 19 start = time.time() 20 p_lst = [] 21 for i in range(100): # 100个任务 22 p = Process(target=func, args=(i,)) 23 p_lst.append(p) 24 p.start() 25 for p in p_lst:p.join() 26 t2 = time.time() - start # 耗时1.8825409412384033 27 28 print(t1, t2) # 0.26628756523132324 1.8825409412384033
View Code
(3) apply 与apply_asyn方法
1 def show(n): 2 print(n*n) 3 4 if __name__ == '__main__': 5 pool = Pool() 6 for i in range(10): 7 #pool.apply(show, args=(i,)) # 同步,不需要下面的代码,也会输出结果! 8 pool.apply_async(show, args=(i, )) # 需要下面的代码,才能有输出! 9 pool.close() # 结束进程池接收任务 10 pool.join() # 感知进程池中的任务执行结束
(4)进程池的返回值
1 from multiprocessing import Pool 2 3 4 def func(num): 5 return num*num 6 7 # demo1 : 使用apply_async,得到返回记过,然后get,就变同步计算了! 8 if __name__ == '__main__': 9 pool = Pool(7) 10 for i in range(10): 11 res = pool.apply_async(func, args=(i,)) 12 #print(res) # <multiprocessing.pool.ApplyResult object at 0x0000022474085E10> 13 print(res.get()) # 同步显示 14 15 16 # demo2:解决,异步计算,同步取结果 17 if __name__ == '__main__': 18 pool = Pool(7) 19 res_lst = [] 20 for i in range(10): 21 res = pool.apply_async(func, args=(i, )) 22 res_lst.append(res) 23 print([res.get() for res in res_lst]) 24 25 # demo3, 用map,异步计算了,然后结果是返回值的列表 26 re = pool.map(func, range(10)) 27 for i in re:print(i)
(5)进程池回调函数
1 import os 2 from multiprocessing import Pool 3 4 def func(num): 5 print('in func:pid=', os.getpid()) 6 return num*2 7 8 def func2(num): 9 print('in func2:pid=', os.getpid()) 10 num*num 11 12 if __name__ == '__main__': 13 print('main pid=', os.getpid()) 14 pool = Pool(7) 15 res_lst = [] 16 for i in range(5): 17 res = pool.apply_async(func, args=(i, ), callback=func2) # 所谓回调函数,是用func的结果, 18 # 作为func2的参数,# func2是在主进程中运行的! 19 res_lst.append(res) 20 for res in res_lst:print(res.get())

浙公网安备 33010602011771号