7-使用协程实现多任务
2021/12/10 23:24:38
本文主要是介绍7-使用协程实现多任务,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
协程
1. 借助生成器实现两个函数的并发
# 借助生成器实现 两个子函数的并发 import time def task1(): while True: print("---1---") time.sleep(1) yield def task2(): while True: print("---2---") time.sleep(1) yield def main(): t1 = task1() t2 = task2() while True: next(t1) next(t2) if __name__ == "__main__": main()
协程的原理就是上一讲的生成器,而且只有一个线程,因此按照所需时间和内存成本:进程>线程>协程。
2. greenlet
实现多任务
我们可以使用greenlet.greenlet
代替协程中的yield
,实现两个任务的并发
from greenlet import greenlet import time def test1(): print("---1---") time.sleep(1) gr2.switch() def test2(): print("---2---") time.sleep(1) gr2.switch() gr1 = greenlet(test1) gr2 = greenlet(test2) # 切换到gr1中执行 gr1.switch()
但是一般不用greenlet
而是用更方便的gevent
3. 使用gevent
实现多任务[重点]
相比需要手动切换的greenlet
,gevent
遇到延时时可以自动切换,更加智能。
obj = gevent.spawn(function,args)
创建协程但不立即执行;obj.join()
开始执行协程,并根据延时情况,自动切换;而gevent.sleep()
能够代替上面的time.sleep()
,实现延时控制。
import gevent def f1(n): for i in range(n): print(gevent.getcurrent(),i) # time.sleep(0.5) 不管用 gevent.sleep(0.5) # 协程的核心在于,利用空闲的时间执行其他协程 def f2(n): for i in range(n): print(gevent.getcurrent(),i) gevent.sleep(0.5) def f3(n): for i in range(n): print(gevent.getcurrent(),i) gevent.sleep(0.5) print("---1---") g1 = gevent.spawn(f1,5) # 注意:创建之后并不执行 print("---2---") g2 = gevent.spawn(f2,5) print("---3---") g3 = gevent.spawn(f3,5) # gevent比greenlet更加智能 # 因为遇到了延时,gevent可以自动切换 g1.join() g2.join() g3.join()
如果还想继续使用time.sleep()
来控制延时的话,可以在文件开头加入以下代码,gevent就能自动检测延时:
from gevent import monkey monkey.patch_all()
主函数中每个协程都需要通过.join()
方法启动有点麻烦,可以使用gevent.joinall()
,将所有要启动的协程排成列表传入,例如:
import gevent,time from gevent import monkey monkey.patch_all() def func(): pass gevent.joinall([ gevent.spawn(func,"work1"), gevent.spawn(func,"work2") ])
4. 实例:图片下载器
import urllib.request import gevent from gevent import monkey monkey.patch_all() def downloader(img_name,img_url): req = urllib.request.urlopen(img_url) img_content = req.read() with open(img_name+'.jpg','wb') as f: f.write(img_content) def main(): gevent.joinall([ gevent.spawn(downloader,'1','https'), gevent.spawn(downloader,'2','https') ]) if __name__ == "__main__": main()
5. 进程、线程和协程的对比
- 进程是操作系统分配资源的单位;
- 线程是调度使用资源的单位;
- 多任务切换消耗的资源排名:进程>线程>协程
- 多线程在python中较少使用,因为CPython的全局解释锁GIL的限制;
- 协程切换任务的耗费资源较少,效率高;
- 多进程和多线程视处理器的核数,可能是 并行,而协程是基于线程的,一定是单核的,所以一定是 并发。
这篇关于7-使用协程实现多任务的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-23Springboot应用的多环境打包入门
- 2024-11-23Springboot应用的生产发布入门教程
- 2024-11-23Python编程入门指南
- 2024-11-23Java创业入门:从零开始的编程之旅
- 2024-11-23Java创业入门:新手必读的Java编程与创业指南
- 2024-11-23Java对接阿里云智能语音服务入门详解
- 2024-11-23Java对接阿里云智能语音服务入门教程
- 2024-11-23JAVA对接阿里云智能语音服务入门教程
- 2024-11-23Java副业入门:初学者的简单教程
- 2024-11-23JAVA副业入门:初学者的实战指南