一、进程补充:
1,生产者消费者模型:
两类角色,一类负责生产数据,另外那类负责数据
生产完放到共享空间,另外那类到空间取数据进行处理
好处: 生产数据的同时可以进行数据的处理,不用等(并发效果)
问题:要有共享空间(1.文件--硬盘,速度慢;2.内存)
要有锁
队列可以完美解决既是内存空间又自带加锁功能
2,要实现进程间通信(IPC),multiprocessing模块支持两种形式:队列和管道,这两种方式都是使用消息传递的
二、共享数据(了解,主要使用队列)
1 from multiprocessing import Process,Manager,Lock 2 def work(dic,mutex): 3 with mutex: 4 dic['count']-=1 5 6 if __name__ == '__main__': 7 mutex=Lock() 8 m=Manager() 9 share_dic=m.dict({'count':100}) 10 l_p=[] 11 for i in range(100): 12 p=Process(target=work,args=(share_dic,mutex)) 13 l_p.append(p) 14 p.start() 15 for i in l_p: 16 i.join() 17 print(share_dic)
三、进程池(重要知识点)
1.进程池:放进程的池子 -- 控制进程的数量
2. n个cpu 开n个进程 效率最高
3.进程池可以指定大小,如不指定 默认是cpu的个数
4.应用
apply,忘记apply
弊端:apply效率低,串行--主程序要等一个程序运行完才能运行下一个
1 from multiprocessing import Pool 2 import time,os,random 3 def task(n): 4 print('%s is running'%os.getpid()) 5 time.sleep(random.randint(1,3)) 6 print('%s is done'%os.getpid()) 7 return n**2 8 9 if __name__ == '__main__': 10 p=Pool(4) 11 obj_l=[] 12 for i in range(1,7): 13 obj=p.apply_async(task,args=(i,)) #async提交的是任务 ,不是进程 14 obj_l.append(obj) 15 p.close() 16 p.join() 17 print('zhu') 18 for obj in obj_l: 19 print(obj.get()) #等进程都运行完,一起取结果 -- 并发 20 #如果运行完一个进程就取一个结果的话 和apply的效果是一个性质-- 串行
# p.close() # 禁止往进程池内再添加任务
5. apply_async 的应用:
1 from multiprocessing import Pool 2 from socket import * 3 s=socket(AF_INET,SOCK_STREAM) 4 s.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) 5 s.bind(('127.0.0.1',8088)) 6 s.listen(5) 7 def talk(conn): 8 while True: 9 try: 10 cmd=conn.recv(1024) 11 if not cmd:break 12 conn.send(cmd.upper()) 13 except Exception: 14 break 15 conn.close() 16 17 if __name__ == '__main__': 18 p=Pool(4) 19 while True: 20 conn,addr=s.accept() 21 p.apply_async(talk,args=(conn,)) 22 s.close() 23 #不用考虑主进程等进程池的关闭
#也不用考虑返回值接收的问题
6.回调函数(属于主进程)
应用场景:爬虫
1 from multiprocessing import Pool 2 import requests 3 import os 4 import time 5 def get_page(url): 6 print('<%s> is getting [%s]' %(os.getpid(),url)) 7 response=requests.get(url) 8 time.sleep(2) 9 print('<%s> is done [%s]' % (os.getpid(), url)) 10 return {'url':url,'text':response.text} 11 def parse_page(res): 12 print('<%s> parse [%s]' %(os.getpid(),res['url'])) 13 with open('db.txt','a') as f: 14 parse_res='url:%s size:%s ' %(res['url'],len(res['text'])) 15 f.write(parse_res) 16 if __name__ == '__main__': 17 p=Pool(4) 18 urls = [ 19 'https://www.baidu.com', 20 'http://www.openstack.org', 21 'https://www.python.org', 22 'https://help.github.com/', 23 'http://www.sina.com.cn/' 24 ] 25 for url in urls: 26 p.apply_async(get_page,args=(url,),callback=parse_page) 27 p.close() 28 p.join() 29 print('主',os.getpid())
通常进程池的里面的任务是耗时间的,不耗时间(比进程池里的任务耗时短)的任务放到回调函数中
下载完就会调解析功能,节省时间