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 ])