生成器复习
在python中,使用了yield的函数被称为生成器(generator).
跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单理解生成器就是一个迭代器.
在调用生成器运行的过程中,每次遇到yield时函数会餐厅并保存当前所有的运行信息,返回yield的值,并在下一次执行next()方法时从当前位置继续运行.
调用一个生成器函数,返回的是一个迭代器对象.
————摘自 noob python3教学。
使用生成器的yield机制来实现多任务
生成器制作方式,在函数中使用yield关键字,生成器。
def work1():
for i in range(10):
print(F'----work1---{i}')
yield
def work2():
for i in range(10):
print(F'----work2---{i}')
yield
# 通过生成器实现多任务
g1 = work1()
g2 = work2()
while True:
next(g1)
next(g2)
这中方式可以称为简单的协程,又叫做微线程。
协程本质上是单任务,只是利用了yield机制在多个任务切换交替执行。
协程依赖于线程。
协程对于线程来说占用的资源更少,几乎没有。
协程概念理解
1,什么是协程
协程是python中一种实现多任务的方式,只不过比线程更小占用,更小执行单元(理解为需要的资源),自带cpu上下文。
通俗的理解,在一个线程中的某个函数,可以在任何地方保存当前函数的一些临时变量等信息。
然后切换到另一个函数中执行,注意不是通过调用函数的方式做到的切换,并且切换的次数以及什么时候切换回来都是由开发者决定。
2,协程与线程差异
在实现多任务时,线程切换从系统层面远不止保存和恢复cpu上下文这么简单,操作系统为了让程序运行的高效每个线程都有自己缓存cache等数据,操作系统还会帮忙做这些数据的恢复工作,所以线程的切换比较耗性能,但是协程的切换只是鹌鹑的操作zpu的上下文,所以一秒钟切换上百万次系统都扛得住
3,greenlet
为了更好的使用协程来完成多任务,python中greenlet对其进行了封装,从而使得切换吧任务变得更加简单,
pip install greenlet
def work1():
for i in range(10):
print(F'----work1---{i}')
g2.switch()
def work2():
for i in range(10):
print(F'----work2---{i}')
g1.switch()
g1 = greenlet(work1)
g2 = greenlet(work2)
g1.switch()
但是greenlet不够优雅,必须要在协程内部写switch方法才能完成切换,可以使用gevent来代替
4,gevent
import gevent
from gevent import monkey
monkey.patch_all() # gevent 的不定
def work1():
for i in range(10):
print(F'----work1---{i}')
gevent.sleep(0.1)
def work2():
for i in range(10):
print(F'----work2---{i}')
gevent.sleep(0.1)
# 创建两个携程
# 线程默认不会等待携程执行
# 携程存在于线程之中
# spawn 开启协程(第一个参数为携程要执行的任务
# join 让线程等待携程执行
# 携程是在什么时候切换的呢?
# 携程之间切换的条件
# gevent.sleep() 耗时等待的情况下才会切换,,不写这个方法就不会切换
# monkey.patch_all() # gevent 补丁 使用一下这个代码就不需要在写gevent也可以交替执行
# 首先考虑携程 --- 线程 --- 进程
g1 = gevent.spawn(work1)
g2 = gevent.spawn(work2)
g1.join()
g2.join()
# 与主线程相比是异步