python 异步IO

参考链接:https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/00143208573480558080fa77514407cb23834c78c6c7309000

异步IO 

  即异步的IO,IO即IO操作,异步:有两个程序,当执行其中一个程序的时候,如果不耽误执行另一个程序,那么这种执行方式就是异步。异步IO即执行IO操作的时候还可以同时执行其他的程序,那么为什么会有异步IO呢?这种模式是为了解决那些缺陷呢?有什么优点呢?

  在一个线程中,CPU执行代码的速度极快,然而,一旦遇到IO操作,如读写文件、发送网络数据时,就需要等待IO操作完成,才能继续进行下一步操作。这种情况称为同步IO。而在IO操作的过程中,当前线程被挂起,而其他需要CPU执行的代码就无法被当前线程执行了。因为一个IO操作就阻塞了当前线程,导致其他代码无法执行,所以我们必须使用多线程或者多进程来并发执行代码,为多个用户服务。每个用户都会分配一个线程,如果遇到IO导致线程被挂起,其他用户的线程不受影响。(解决办法一)聪明的你肯定会发现,这里面压根就没有异步什么事,按照常识来说,那么这种解决办法一定有缺点,而异步,就是用来解决这些缺点的:

  没错,多线程和多进程的模型虽然解决了并发问题,但是系统不能无上限地增加线程。由于系统切换线程的开销也很大,所以,一旦线程数量过多,CPU的时间就花在线程切换上了,真正运行代码的时间就少了,结果导致性能严重下降。

  所以,另一种解决IO问题的方法是异步IO。当代码需要执行一个耗时的IO操作时,它只发出IO指令,并不等待IO结果,然后就去执行其他代码了。一段时间后,当IO返回结果时,再通知CPU进行处理。

   

为了更好理解异步和同步,有课代表举出了一个例子:

老张爱喝茶,废话不说,煮开水。

出场人物:老张,水壶两把(普通水壶,简称水壶;会响的水壶,简称响水壶)。

1 老张把水壶放到火上,立等水开。(同步阻塞)

老张觉得自己有点傻

2 老张把水壶放到火上,去客厅看电视,时不时去厨房看看水开没有。(同步非阻塞)

老张还是觉得自己有点傻,于是变高端了,买了把会响笛的那种水壶。水开之后,能大声发出嘀~~~~的噪音。

3老张把响水壶放到火上,立等水开。(异步阻塞)

老张觉得这样傻等意义不大

4 老张把响水壶放到火上,去客厅看电视,水壶响之前不再去看它了,响了再去拿壶。(异步非阻塞)

老张觉得自己聪明了。

所谓同步异步,只是对于水壶而言。 普通水壶,同步;响水壶,异步。

虽然都能干活,但响水壶可以在自己完工之后,提示老张水开了。这是普通水壶所不能及的。

同步只能让调用者去轮询自己(情况2中),造成老张效率的低下。

所谓阻塞非阻塞,仅仅对于老张而言。

立等的老张,阻塞;看电视的老张,非阻塞。 情况1和情况3中老张就是阻塞的,媳妇喊他都不知道。

虽然3中响水壶是异步的,可对于立等的老张没有太大的意义。所以一般异步是配合非阻塞使用的,这样才能发挥异步的效用。

异步IO的实现方法:

  可以想象按照同步IO的编程顺序写出的代码是没有办法实现异步IO的

do_some_code()
f = open('/path/to/file', 'r')
r = f.read() # <== 线程停在此处等待IO操作结果*****看着里
# IO操作完成后线程才能继续执行:
do_some_code(r)

  所以,同步IO模型的代码是没法实现异步IO的,在前面的例子中,响水壶之所以被称为是异步的,就是因为它有一个提示用户的方法,异步IO需要一个消息循环,在消息循环中,主线程不断重复“读取消息-处理消息”这一过程:

loop = get_event_loop()
while True:
    event = loop.get_event()
    process_event(event)

  

  消息模型其实早在应用在桌面应用程序中了。一个GUI程序的主线程就负责不停地读取消息并处理消息。所有的键盘、鼠标等消息都被发送到GUI程序的消息队列中,然后由GUI程序的主线程处理。

  由于GUI线程处理键盘、鼠标等消息的速度非常快,所以用户感觉不到延迟。某些时候,GUI线程在一个消息处理的过程中遇到问题导致一次消息处理时间过长,此时,用户会感觉到整个GUI程序停止响应了,敲键盘、点鼠标都没有反应。这种情况说明在消息模型中,处理一个消息必须非常迅速,否则,主线程将无法及时处理消息队列中的其他消息,导致程序看上去停止响应。

  消息模型是如何解决同步IO必须等待IO操作这一问题的呢?当遇到IO操作时,代码只负责发出IO请求,不等待IO结果,然后直接结束本轮消息处理,进入下一轮消息处理过程。当IO操作完成后,将收到一条“IO完成”的消息,处理该消息时就可以直接获取IO操作结果。

  在“发出IO请求”到收到“IO完成”的这段时间里,同步IO模型下,主线程只能挂起,但异步IO模型下,主线程并没有休息,而是在消息循环中继续处理其他消息。这样,在异步IO模型下,一个线程就可以同时处理多个IO请求,并且没有切换线程的操作。对于大多数IO密集型的应用程序,使用异步IO将大大提升系统的多任务处理能力。

补充:

  协程只是程序调度的方式,多线程和多进程由操作系统调度,而协程由程序自身即程序员调度,仅此而已。异步io指的是程序只发io指令并不阻塞等待io结果,在io结束前需要io结果的代码当然不能执行,所以我们通过协程调度,然后让cup去执行别的代码,等io结束再切换回来,其实就只是增加cup的利用。io不是cpu在干活,而是磁盘网络之类,正是因为cpu的速度远高于磁盘及网络,所以我们通过异步的方式来io,就是io的时候不让cpu傻站着等,io结束后,需要io结果的代码需要接着执行,所以需要使用协程切换回来,协程只是可以让程序在某个地方停下来,然后在需要的时候(io完成后)再接着执行。

  即不让CPU一直等着,可以去做别的事情,假如没有异步的方式去IO,CPU就会一直等着,啥事也不做,知道IO完成后才开始。

原文地址:https://www.cnblogs.com/Gaoqiking/p/10620853.html