1.协程
1.本质上是一个线程。
2.能偶在多个任务之间切换来节省一下IO时间。
3.协程中任务之间的切换也消耗时间,但开销要远远小于进程和线程之间的切换。
真正的协程模块就是使用greenlet来完成多个任务之间的切换。
from greenlet import greenlet def eat(): print('eating start') g2.switch() # 切换到g2对象的函数中接着执行,并记录下来当前位置 print('eating end') g2.switch() # 切换到g2对象的函数中接着执行,并记录下当前位置 def play(): print('playing start') g1.switch() # 切换到g1对象的函数中接着执行,并记录下当前位置 print('playing end') g1 = greenlet(eat) # 创建对象并将函数注册到对象中 g2 = greenlet(play) # 创建对象并将函数注册到对象中 g1.switch() # 切换到g1对象的函数中
结果:
2.协程模块
import gevent def eat(): print('eating start') gevent.sleep(1) # gevent感知不到time.sleep,这里暂停要用gevent.sleep print('eating end') def play(): print('playing start') gevent.sleep(1) print('playing end') g1 = gevent.spawn(eat) # 创建一个协程对象g1,spam括号内第一个参数是函数名,后面可以有多个参数,都是传递给函数的 g2 = gevent.spawn(play) g1.join() # 等待g1结束 g2.join()
# 这里的join可以换城:geven.joinall([g1,g2]),括号内是一个可迭代对象,可以同时等待g1和g2结束。
结果: 两个函数同时执行。
上面代码中如果想用time.sleep或其他阻塞也可以,但是需要如下操作:
from gevent import monkey #导入gevent中的monkey模块 import gevent import time monkey.patch_all() # 执行monkey模块中的patch_all方法,就可以使gevent模块识别到time.sleep def eat(): print('eating start') time.sleep(1) print('eating end') def play(): print('playing start') time.sleep(1) print('playing end') g1 = gevent.spawn(eat) # 创建一个协程对象g1,spam括号内第一个参数是函数名,后面可以有多个参数,都是传递给函数的 g2 = gevent.spawn(play) g1.join() # 等待g1结束 g2.join()
结果:
接收返回值:
from gevent import monkey #导入gevent中的monkey模块 import gevent import time monkey.patch_all() # 执行monkey模块中的patch_all方法,就可以使gevent模块识别到time.sleep def eat(): print('eating start') time.sleep(1) print('eating end') return 'wdc' def play(): print('playing start') time.sleep(1) print('playing end') return 'yhf' g1 = gevent.spawn(eat) # 创建一个协程对象g1,spam括号内第一个参数是函数名,后面可以有多个参数,都是传递给函数的 g2 = gevent.spawn(play) g2.join() # 等待g1结束 g2.join() name1 = g1.value # 接收函数的返回值,需要放在join的后面 name2 = g2.value print(name1, name2)
结果: 成功打印返回值。