协程
线程数量非常多的时候,会有两个问题:一是系统线程会占用非常多的内存空间,二是过多的线程切换会占用大量的系统时间。
协程刚好可以解决上述2个问题。协程运行在线程之上,当一个协程执行完成后,可以选择主动让出,让另一个协程运行在当前线程之上。
协程并没有增加线程数量,只是在线程的基础之上通过分时复用的方式运行多个协程,而且协程的切换在用户态完成,切换的代价比线程从用户态到内核态的代价小很多。
def work1():
while True:
print("work1:...")
yield
def work2():
while True:
print("work2:...")
yield
if __name__ == "__main__":
w1 = work1()
w2 = work2()
while True:
next(w1)
next(w2)
使用greenlet实现协程
from greenlet import greenlet
import time
def work1():
while True:
print("work1:...")
time.sleep(0.5)
g2.switch() # g1阻塞执行g2
def work2():
while True:
print("work2:...")
time.sleep(0.5)
g1.switch() # g2阻塞执行g1
if __name__ == "__main__":
g1 = greenlet(work1)
g2 = greenlet(work2)
# g1先执行
g1.switch()
使用greenlet无需yield,使用switch()
来切换协程或启动协程。协程内的switch()
会在阻塞时启用。
指定一个先执行后,就可以自动执行其他协程。
使用gevent实现协程
指派任务:gevent(函数名,参数1,参数2,...)
之后使用.join()
来是主线程等待协程执行完毕再退出。使用gevent.sleep()
来阻塞协程、切换协程。
import gevent
import time
def work1():
while True:
print("work1:...")
gevent.sleep(0.5)
def work2():
while True:
print("work2:...")
gevent.sleep(0.5)
if __name__ == "__main__":
g1 = gevent.spawn(work1)
g2 = gevent.spawn(work2)
g1.join()
g2.join()
默认情况下使用 time.sleep()是不行的哦!除非:给gevent或程序打补丁
# 给程序打补丁,放在程序开头。
# 放在下面也不一定报错,但可能影响其他模块
from gevent import monkey
monkey.patch_all()