Python档案袋( 进程与协程 )
Python的进程和线程是使用的操作系统的原生线程和进程,其是去调用操作系统的相应接口实现
进程:之间不可直接共享数据,是资源的集合,进程必须有一个线程
线程:基于进程,之间可直接共享数据,可执行,只有所有的线程执行完毕程序才会退出
守护线程:生命值依赖于创建它的主线程,主程序亡,不管守护进程执行到何步也必须立即亡
多线程:不适用与CPU操作任务大的(如计算等),较适合于IO操作任务大的(如文件读写等)
进程
简单的进程
在Windows上启动进程必须加入【if __name__=="__main__":】,而在linux上则可随意,进程的使用基本与线程相同
import multiprocessing import time def run11(): print("----- 进程 ----") # win 进程启动,必须加入这句 if __name__=="__main__": #启动进程 t1=multiprocessing.Process(target=run11,args=()) t1.start()
进程间传递数据之进程队列:
1 import multiprocessing 2 3 def run11(qqlistx): 4 print("****** 进入进程 ********") 5 #设置进程数据 6 qqlistx.put("11111122") 7 8 # win 进程启动,必须加入这句 9 if __name__=="__main__": 10 11 #进程队列 12 qqlistx = multiprocessing.Queue() 13 14 #启动进程,必须传递进程队列 15 t1=multiprocessing.Process(target=run11,args=(qqlistx,)) 16 t1.start() 17 18 print("得到进程数据:", qqlistx.get())
进程间传递数据之管道:
1 import multiprocessing 2 3 def run11(pp1): 4 print("****** 进入进程 ********") 5 6 #发送数据 7 pp1.send("东小东") 8 print("收到mian进程发来的数据:",pp1.recv()) 9 10 # win 进程启动,必须加入这句 11 if __name__=="__main__": 12 13 #得到管道 14 # 得到两端,如同socket的服务器和客户端 15 #任意一端都可以进行收发 16 pp1,pp2 = multiprocessing.Pipe() 17 18 #启动进程,传递任意一端 19 t1=multiprocessing.Process(target=run11,args=(pp1,)) 20 t1.start() 21 22 #另一端接收数据 23 print("得到进程数据:", pp2.recv()) 24 pp2.send("收到数据了东小东")
进程之数据共享:
两个进程进行数据共享,列表或者字典数据共享
1 import multiprocessing 2 3 def run11(vv): 4 print("****** 进入进程 ********") 5 6 vv["dong"]="dongxiaodong" 7 #vv.append("555") #列表 8 9 # win 进程启动,必须加入这句 10 if __name__=="__main__": 11 12 #方法一 -------------: 13 # with multiprocessing.Manager() as mssaagex: 14 # dictx=mssaagex.dict() #得到字典参数 15 # #listx=mssaagex.list() #得到列表参数 16 # 17 # #启动进程,传递字典或者列表 18 # t1=multiprocessing.Process(target=run11,args=(dictx,)) 19 # t1.start() 20 # 21 # #等待进程接收 22 # t1.join() 23 # 24 # #打印字典数据 25 # print("得到进程数据:", dictx) 26 27 #方法二 -------------------: 28 dictx=multiprocessing.Manager().dict() #得到字典参数 29 #listx=multiprocessing.Manager().list() #得到列表参数 30 31 #启动进程,传递字典或者列表 32 t2=multiprocessing.Process(target=run11,args=(dictx,)) 33 t2.start() 34 35 #等待进程接收 36 t2.join() 37 38 #打印字典数据 39 print("得到进程数据:", dictx)
进程锁:
可以保护屏幕打印等,如多个进程同时向屏幕输出数据时,可以保证屏幕数据来自于一个进程,不会出现数据混乱问题
1 import multiprocessing 2 3 def run11(vv): 4 vv.acquire() #上锁 5 print("****** 进入进程 ********") 6 vv.release() #解锁 7 8 9 # win 进程启动,必须加入这句 10 if __name__=="__main__": 11 12 lockx=multiprocessing.Lock() #得到进程锁 13 14 t2=multiprocessing.Process(target=run11,args=(lockx,)) 15 t2.start()
进程池:
确定进程的同时运行个数,更好的进行进程管理
1 import multiprocessing 2 import time 3 4 def run11(vv): 5 time.sleep(1) 6 print("****** 进入进程 ********",vv) 7 8 #回调函数 9 #在主进程中运行 10 def Cal(arg): 11 print("每个进程的回调函数",arg) 12 13 # win 进程启动,必须加入这句 14 if __name__=="__main__": 15 16 poolx=multiprocessing.Pool(2) #得到进程池,最多同时执行2个进程 17 18 #启动进程 19 for i in range(10): 20 #poolx.apply_async(func=run11,args=(i,)) #并行 21 poolx.apply_async(func=run11,args=(i,),callback=Cal) #并行并加入执行完毕的回调函数 22 #poolx.apply(func=run11,args=(i,)) #串行 23 24 #等待并关闭进程 25 poolx.close() 26 poolx.join() 27 print("----- 完毕 -----")
协程:
单线程实现高并发
安装:pip3 install gevent
手动切换:
import greenlet def gfunx1(): print("----gfunx1---") g2.switch() #手动切换到 gfunx2 中 def gfunx2(): print("---gfunx2----") #声明两个协程 g1=greenlet.greenlet(gfunx1) g2=greenlet.greenlet(gfunx2) g1.switch() #手动切换到 gfunx1 中
自动切换:
默认是先运行完gfunx1然后再运行gfunx2,但当遇到IO操作则会自动跳转到另一个协程工作,以此实现在协程中遇到IO就互相切换执行的效果
1 import gevent 2 3 def gfunx1(): 4 print("---- gfunx1 ---") 5 gevent.sleep(3) #模拟 IO 操作为 3 秒,但使用time.sleep(x)则会进行阻塞 6 print("**** 三秒io操作结束 ******") 7 8 def gfunx2(): 9 print("---- gfunx2 ----") 10 11 12 #开启两个协程 13 gevent.joinall([ 14 gevent.spawn(gfunx1), 15 gevent.spawn(gfunx2), 16 ])
自动切换进阶:
将一系列阻塞操作让协程识别为IO操作
1 import gevent 2 from gevent import monkey 3 #将所有的阻塞操作(如:网络,延时,文件等)都视为gevent可捕获的IO阻塞操作 4 #根据库作者提示:此句最好放在其它库import之前,否则会出现警告 5 monkey.patch_all() 6 7 import requests 8 import time 9 10 def gfunx1(): 11 print("---- gfunx1 ---") 12 res=requests.get("https://img2018.cnblogs.com/blog/1485202/201811/1485202-20181116215233782-319594948.png") 13 open("ww.jpg","wb").write(res.content) #以二进制写文件 14 print("**** 网络操作结束 ******") 15 16 def gfunx2(): 17 print("---- gfunx2 ----") 18 time.sleep(3) #延时操作也已视为IO阻塞 19 print("*** 延时操作结束 3s ***") 20 21 def gfunx3(varx): 22 print("---- gfunx3 ----",varx) 23 time.sleep(1) 24 print("*** 延时操作结束 1s ***") 25 26 27 #开启三个协程 28 gevent.joinall([ 29 gevent.spawn(gfunx1), 30 gevent.spawn(gfunx2), 31 gevent.spawn(gfunx3,"33333") #传递参数 32 ])