❖ 异步IO Asynchronous I/O
"IO编程中,Stream(流)是一个很重要的概念,可以把流想象成一个水管,数据就是水管里的水,但是只能单向流动。Input Stream就是数据从外面(磁盘、网络)流进内存,Output Stream就是数据从内存流到外面去。" - 阮一峰
编程时我们常面对的I/O有:
- 磁盘I/O:就是我们常用的
file.open("/path/to/file")
等语句直接读取本地文件。 - 网络I/O:就是
socket.receive()
和socket.accpet()
这样的与别的电脑沟通的语句。 - 内存I/O:就是
StringIO.write()
和STRINGIO.getvalue()
等直接在内存里读写的语句。
内存的IO读写极快,远远远高于磁盘和网络的IO读取写入。比如要把100M的数据写入磁盘,CPU输出100M的数据只需要0.01秒,可是磁盘要接收这100M数据可能需要10秒。
如果不涉及IO读取写入,CPU执行代码速度是极快的,一旦碰上了需要读写的地方,就要停下来等着龟速的IO完成,再执行下一句。
这就造成了严重的拖累,这不合理。处理的事情少的时候还好说,一旦遇到高并发要求这是一个必须要解决的问题。
所以就出现了异步IO
这个策略。
所有的IO都存在一样的共性:堵塞。
根据IO是否堵塞,分为了这两种:
- 同步IO (Synchronous I/O):程序遇到IO读写时,要停下来等待其完成才执行下一句。
- 异步IO (Asynchronous I/O):程序遇到IO读写时,不等待而直接执行下一句。
但是,如果没有接收到上一步IO的值,之后的代码都没法正常执行啊?
所以,正常的运行逻辑是不行的,必须改变代码逻辑才能使用异步IO
。
我们称这种逻辑为:异步IO模型
。
异步IO模型:Event Loop
同步IO模型,是线性的,从上到下,一通到底。
异步IO模型,是循环的,一直在做死循环
,我们称之为消息循环
(Event Loop)。
典型异步IO模型
的代码:
loop = get_event_loop()
while True:
event = loop.get_event()
process_event(event)
异步IO模型需要一个
Event Loop
,即主线程不断地重复读取消息->处理消息
这一过程。
Event Loop
其实早在应用在桌面应用程序中了。一个GUI程序的主线程就负责不停地读取消息并处理消息。所有的键盘、鼠标等消息都被发送到GUI程序的消息队列中,然后由GUI程序的主线程处理。
这种Event Loop
,是一种什么样的逻辑呢?
记住,这种东西总是在处理高并发
的问题,也就是同时发起很多很多个任务的问题。异步IO解决的就是这种尽快处理完任务的问题。
也就是说,先决条件
是:
每个任务必须是平行平等的,才能利用到异步IO
。如果任务之间有前后、上下的关系,那么必然也必须是线性的。只有做到平等,才能做到平行,即利用到循环。
记住这点,对理解异步IO很重要。一旦理解异步IO,就能很快的理解多进程、多线程、协程、异步socket等一系列常见话题。