下面是第5部分的内容。内容中涉及的程序均来源于廖老师的Python教程(网址为https://www.liaoxuefeng.com/wiki/1016959663602400/)。
十五、异步IO
结合之前介绍的IO密集型的内容,由于大多数的任务都是IO密集型的,所以可以使用异步IO的方式完成多任务。
同步IO和异步IO的对比:同步IO下,当前线程被挂起,其它需要CPU执行的代码无法被当前线程执行;异步IO下,需要一个消息循环,其中主线程不断地重复“读取消息-处理消息”的过程(遇到IO操作时,代码只负责发送IO请求,不等待IO结果,直接结束本轮消息处理,进入下一轮消息处理过程。当IO操作完成后,会收到“IO完成”的消息,处理该消息即可以直接获取IO操作结果)。
1. 协程
子程序是通过栈来实现,一个线程就是执行一个子程序。在代码中,子程序的调用顺序是确定的。但是,协程在执行子程序时,不是函数的调用,而是类似于CPU的中断。
协程是一个线程在执行,而不是多线程。优势在于:没有线程切换的消耗,不需要多线程的锁机制,具有极高的执行效率。
为了充分利用多核和协程,可以采用多进程+协程的方式。
Python对于协程的实现是通过generator完成的。其中,Python的yield不但可以返回一个值,还可以接收调用者发出的参数。
实现协程的过程:1. 启动生成器;
2. 发送数据;
3. 接收返回的数据;
4. 数据发送完,关闭线程;
2. asyncio
asyncio是Python 3.4版本引入的标准库,直接内置了对异步IO的支持。
实现异步IO:(1)获取EventLoop;
(2)把需要执行的协程(用@asyncio.coroutine把一个generator标记为coroutine类型,异步操作是通过coroutine中的yield from完成)扔到EventLoop中执行。具体的实现代码请见廖老师的教程部分。
实现了两个或多个coroutine的单线程并发。
3. async/await
Python 3.5之后,引入async、await来使coroutine的代码更简洁易读。具体实现是如下的两个替换:
1. 将@asyncio.coroutine替换为async;
2. 将yield from 替换为await。
4. aiohttp
asyncio可以实现单线程的并发IO操作。若是仅用在客户端,则发挥的威力不大;若是用在服务器端,如Web服务器,由于HTTP连接是IO操作,因而可以用单线程+coroutine实现多用户的高并发支持。
asyncio支持TCP、UDP等协议,aiohttp是基于asyncio实现HTTP框架。