协程
代码1(yield)
import time
def work_one():
for _ in range(3):
print('-----协程1-----')
yield
time.sleep(0.5)
def work_two():
for _ in range(3):
print('-----协程2-----')
yield
time.sleep(0.5)
def main():
wo, wt = work_one(), work_two()
for _ in range(3):
next(wo)
next(wt)
if __name__ == '__main__':
main()
代码2(greenlet)
import time
from greenlet import greenlet
def main():
def work_one():
while True:
print('-----A-----')
gl_two.switch()
time.sleep(0.5)
def work_two():
while True:
print('-----B-----')
gl_one.switch()
time.sleep(0.5)
gl_one = greenlet(work_one)
gl_two = greenlet(work_two)
gl_one.switch()
if __name__ == '__main__':
main()
通过greenlet实现的协程,需要人工切换
代码3(gevent)
用法1: 使用monkey.patch_all()实现,当遇到耗时情况时自动切换协程
import time
import gevent
from gevent import monkey
# 给程序打补丁, 有耗时操作(例如time.sleep)时
monkey.patch_all()
def work1():
while True:
print('work1...')
time.sleep(1)
def work2():
while True:
print('work2...')
time.sleep(1)
def main():
w1 = gevent.spawn(work1)
w2 = gevent.spawn(work2)
w1.join()
w2.join()
if __name__ == '__main__':
main()
用法2: 不使用monkey.patch_all()的情况下要实现协程的自动切换,需使用gevent中自己的耗时模块
import gevent
def work1():
while True:
print('work1...')
# 将程序中用到的耗时操作的代码,使用gevent中自己实现的模块
gevent.sleep(1)
def work2():
while True:
print('work2...')
# 使用gevent中自己实现的模块,不需要monkey.patch_all()
gevent.sleep(1)
def main():
w1 = gevent.spawn(work1)
w2 = gevent.spawn(work2)
w1.join()
w2.join()
if __name__ == '__main__':
main()
用法3: 批量join协程和传参
import gevent
def work1(msg):
while True:
print(msg)
gevent.sleep(1)
def work2(msg):
while True:
print(msg)
gevent.sleep(1)
def main():
# joinall可批量添加协程
gevent.joinall(
[
# "I'm work1" 即是参数,会传给前面的函数,即work1
gevent.spawn(work1, "I'm work1"),
gevent.spawn(work2, "I'm work2")
]
)
if __name__ == '__main__':
main()
通过gevent实现的协程,不需要人工切换,当检测到耗时操作时会自动切换
总结
- 进程是资源分配的单位,同一个进程下的所有线程共享全部资源
- 线程是操作系统调度的单位
- 进程切换需要的资源很最大,效率很低
- 在不考虑GIL的情况下,线程切换需要的资源一般,效率一般
- 协程切换任务资源很小,效率高
- 进程、线程不受控制,协程受控制
- 协程是并发不是并行