参考文章:
1.廖雪峰教程-异步
3.Improve Your Python: 'yield' and Generators Explained
4.[译] Python 3.5 协程究竟是个啥
概念:同步、异步、阻塞、非阻塞
请参见我的之前的学习笔记为什么要使用异步?
CPU和IO的速度差异大,为了同时执行其他的任务,我们可以采用多线程和多进程,也可以采用异步,正如上面的学习笔记,异步是一种分离调用和结果两个过程的机制,因此可以用异步来解决IO问题。Coroutines and Subroutines 协程和子程序
见上面的参考文章3
子程序就是协程的一种特例
协程和子程序一样都可以跟主程序进行交互,但是协程可以保存上下文。
- 消息模型是如何解决同步IO必须等待IO操作这一问题的呢?
当遇到IO操作时,代码只负责发出IO请求,不等待IO结果,然后直接结束本轮消息处理,进入下一轮消息处理过程。当IO操作完成后,将收到一条“IO完成”的消息,处理该消息时就可以直接获取IO操作结果。
- 优点
在“发出IO请求”到收到“IO完成”的这段时间里,同步IO模型下,主线程只能挂起,但异步IO模型下,主线程并没有休息,而是在消息循环中继续处理其他消息。这样,在异步IO模型下,一个线程就可以同时处理多个IO请求,并且没有切换线程的操作。对于大多数IO密集型的应用程序,使用异步IO将大大提升系统的多任务处理能力。
- 协程
协程看上去也是子程序,但执行过程中,在子程序内部可中断,然后转而执行别的子程序,在适当的时候再返回来接着执行。
- 那和多线程比,协程有何优势?
最大的优势就是协程极高的执行效率。因为子程序切换不是线程切换,而是由程序自身控制,因此,没有线程切换的开销,和多线程比,线程数量越多,协程的性能优势就越明显。
- 实例
import asyncio
@asyncio.coroutine
def getdata():
print('getting data!')
r = yield from asyncio.sleep(1)
print('has got data!')
def main():
loop = asyncio.get_event_loop()
loop.run_until_complete(getdata())
loop.close()
if __name__ == '__main__':
main()
首先我们需要一个处理循环loop,这个就是前面说异步的时候说的调用者,相对IO来说执行的非常快,可以执行多个协程。协程是循环的小弟,帮loop去执行不同的调用,比如这里的getdata,r = yield from asyncio.sleep(1)
这句就相对于IO操作,调用后马上返回loop,loop继续处理,知道IO处理好之后,loop就回到协程的这里继续执行。注意调用和数据返回是分开的
- 例子2
import asyncio
import threading
@asyncio.coroutine
def getdata():
print('getting data in thread {}...'.format(threading.current_thread()))
r = yield from asyncio.sleep(1)
print('has got data!')
def main():
loop = asyncio.get_event_loop()
coroutines = [getdata(),getdata()]
loop.run_until_complete(asyncio.wait(coroutines))
loop.close()
if __name__ == '__main__':
main()
打印出的信息
getting data in thread <_MainThread(MainThread, started 3704)>...
getting data in thread <_MainThread(MainThread, started 3704)>...
has got data!
has got data!
这个例子说明,多个协程是在同一个线程中运行的,协程用于异步IO的验证
asyncio可以实现单线程并发IO操作。如果仅用在客户端,发挥的威力不大。如果把asyncio用在服务器端,例如Web服务器,由于HTTP连接就是IO操作,因此可以用单线程+coroutine实现多用户的高并发支持。
asyncio实现了TCP、UDP、SSL等协议,aiohttp则是基于asyncio实现的HTTP框架。