回顾一下进/线程
进程 计算机中最小的资源分配单位
线程 计算机中被cpu调度的最小单位
线程即操作系统的调度
对于操作系统来说,最小的可见单位即是线程
线程对比进程开销虽然小很多,但是开启/关闭线程仍需要开销
协程(本质是一条线程,操作系统不可见)
是由程序员操作的,而不是由操作系统调度的
多个协程的本质是一条线程,所以多个协程不能利用多核
出现的意义:多个任务中的io时间可以共享,当执行一个任务遇到io操作时可以将程序切换到另一个任务中继续执行
在有限的线程中,实现任务的并发,节省了一些调用操作系统创建/销毁线程的时间,并且协程的切换效率比线程切换效率要高
协程执行多个任务能让线程少陷入阻塞,使县城看起来很忙
线程陷入阻塞的次数越少,那么能够抢占的CPU资源就越多,程序效率看起来就越高
即 效率↑ 开销↓
协程的本质 于多个任务之间能够来回切换
协程模块:greenlet与gevent
greenlet模块
定义:对象名=greenlet(fun)
调用/启动:对象名.switch()
import time from greenlet import greenlet #导入外部模块greenlet中的greenlet方法 def eat(): # 协程任务 协程函数 print('start eating') time.sleep(1) # 睡1s print('end eating') g2.switch() #启动协程对象g2 def sleep(): # 协程任务 协程函数 print('start sleeping') g1.switch() #启动协程对象g1 time.sleep(1) print('end sleeping') g1=greenlet(eat) # 定义协程对象g1 g2=greenlet(sleep) #定义协程对象g2 g1.switch() #启动协程g1
gevent模块
定义:对象名=gevent.spawn(fun)
调用/启动:仅在阻塞等待协程结束时生效,无阻塞则协程死亡
对象名.join #启动一个协程
gevent.joinall([g1,g2]) #启动列表中的所有协程
import time import gevent def eat(): print('start eating') gevent.sleep(1) #gevent模块特有的,与time.sleep(1)相同效果,但gevent不支持time.sleep() print('end eating') def sleep(): print('start sleeping') gevent.sleep(1) print('end sleeping') g1=gevent.spawn(eat) g2=gevent.spawn(sleep) gevent,joinall([g1,g2]) # 阻塞等待协程结束
import gevent from gevent import monkey;monkey.path_all()