谈谈python协程
什么是协程
wiki解释如下:
Coroutines are computer program components that generalize subroutines for non-preemptive multitasking, by allowing multiple entry points for suspending and resuming execution at certain locations.
简单的解释就是一个可以多次暂停执行,并且可以恢复继续执行的函数。
从yield到异步编程
网上很多文章都说python 的协程可以使用编写同步代码的方式编写异步程序。
有一个问题一直困扰着我,只用yield就可以实现异步编程吗?
自己也尝试去这样做,发现事情似乎没有这么简单。
假设一种场景,服务器上多个任务需要读取数据库,但是读取数据库比较费时,如果仅使用yield实现的协程,是否可以实现异步IO,提高运行效率?
import time
from collections import deque
def readdb():
time.sleep(3)
return 3
def acceptReq():
print "accept request"
def getData(num):
data= -1
while True:
print "get data{} start".format(str(num))
yield data
data = readdb()
print "get data{} end".format(str(num))
tasks = deque()
tasks.extend([getData(1), acceptReq(), getData(3)])
def run():
#acceptReq()
#ret = 0
while tasks:
task = tasks.popleft()
try :
ret = next(task)
#print ret
tasks.append(task)
#acceptReq()
except StopIteration:
print("end")
if __name__=='__main__':
run()
其实分析代码可以看出,效率并没有得到提升,我们希望的是当一个getdata的task在进行IO操作时,另一个acceptReq的task可以接受请求,当数据读取完成,就可以切换回getdata继续后续的操作,由于没有一个通知机制,所以并不能告诉调用函数IO操作已完成,所以还是会造成占用CPU等待的情况。
python的yield的关键字就可以实现函数的暂停和恢复执行。但是要实现异步编程光能够暂停和恢复函数的执行是不够的,还需要一个时间循环的特性,python3.4加入了asynico,asyncio + 生成器已经达到了异步编程的条件,在 Python3.4 中,我们就可以这样实现一个异步的模型。
协程的进化流程
asynico
yield ---------> 协程 ----------> 异步IO