malongshuai / malongshuai.github.io

2 stars 0 forks source link

五种IO模型透彻分析 | 骏马金龙 #29

Closed malongshuai closed 3 years ago

malongshuai commented 5 years ago

https://www.junmajinlong.com/coding/IO_Model/

五种IO模型透彻分析

lauyu commented 4 years ago

膜拜,顺便请教下,学习io除了死机硬背,有没有一个比较好的实践方式

malongshuai commented 4 years ago

@lauyu 膜拜,顺便请教下,学习io除了死机硬背,有没有一个比较好的实践方式

这个是理解的,抓住关键点理解,不然就得死记硬背了。大概就下面几个关键点。 IO操作分为几个过程,以读IO为例,硬件--(1)-->内核buffer--(2)-->用户层进程buffer。其中(1)是由DMA完成,不占用CPU,(2)是由内核占用CPU完成。 阻塞/非阻塞是描述进程是否能获取cpu,同步/异步是描述两端数据在保持互相同步的过程中进程是否应阻塞。 IO复用、信号驱动、异步IO的目标都是尽快处理多个IO操作。其中: IO复用是描述多个IO操作能否复用,而不是一个一个地串行处理。这需要一次性监控很多个文件描述符的不同事件,事件发生后就处理对应的文件描述符,所以是事件驱动IO的一种。 信号驱动是进程布置一个信号处理程序,IO完成后通过发送IO信号来通知处理IO。 异步IO是通过特殊的异步IO函数来完成的,在调用异步IO函数的时候,当IO完成后,内核要么信号通知进程,内核要么开一个线程在后台默默地帮助进程执行指定的操作。

bing-dong commented 3 years ago

你好请教一下,以我理解信号驱动IO相比于非阻塞IO就是多了数据准备好就主动通知的功能,这和select等IO复用的功能差不多,但为什么一般总是用IO复用而不是信号驱动IO呢?

malongshuai commented 3 years ago

@bing-dong 你好请教一下,以我理解信号驱动IO相比于非阻塞IO就是多了数据准备好就主动通知的功能,这和select等IO复用的功能差不多,但为什么一般总是用IO复用而不是信号驱动IO呢?

首先信号驱动IO和epoll的性能差不多,都用于处理大量文件描述符。但使用信号驱动IO很复杂的,并不像文章描述那样简单,比如如何处理重复的SIGIO信号丢失问题,就是一个巨大的难题,这是操作系统的硬限制。但epoll没有这方面问题,它是事件驱动的,操作系统对epoll的支持足够完善且简单使用,只要理解了epoll用法,写代码时基本上就是套经验模板。

qianmingjun0816 commented 3 years ago

这是我看的最好的将 IO 模型的文章,很多人讲这个只是把 UNIX 那本书上面的图贴出来而已,这篇文章还有作者一些自己的理解,很 nice ,这里必须点个赞。博客的内容也很好,从底层到上层都有讲解。国内讲这样的东西的人不多。感谢分享

luqian2017 commented 3 years ago

请问: "异步IO是通过特殊的异步IO函数来完成的,在调用异步IO函数的时候,当IO完成后,内核要么信号通知进程,内核要么开一个线程在后台默默地帮助进程执行指定的操作。" 这里异步IO如果采用内核开一个线程默默做的话,实际上CPU还是会在用户层进程和这个内核线程之间不断切换。也就是说,这个期间,用户层进程并没有阻塞,可以做它感兴趣的事,对吗?

1772523056 commented 3 years ago

哈哈发现博主的一个bug,没登录的时候评论按时间倒序,登录后又是正序

malongshuai commented 3 years ago

@luqian2017 请问: "异步IO是通过特殊的异步IO函数来完成的,在调用异步IO函数的时候,当IO完成后,内核要么信号通知进程,内核要么开一个线程在后台默默地帮助进程执行指定的操作。" 这里异步IO如果采用内核开一个线程默默做的话,实际上CPU还是会在用户层进程和这个内核线程之间不断切换。也就是说,这个期间,用户层进程并没有阻塞,可以做它感兴趣的事,对吗?

假设这里的内核指的是OS的内核。异步时如果开一个内核线程帮忙执行操作,这个线程也会和任何线程一样,正常参与线程的调度。您可以认为,有一所大门,门外是用户进程(线程),门内是内核进程(线程),新开一个内核线程,仅仅只是在门内多加了一个执行任务的成员,多了一个被调度的目标。因此,不会像您所说的一样:在这个内核线程和用户进程之间不断切换,而是依旧如常一样,正常地按照调度算法切换。在这个期间,用户层进程不会阻塞,因为该进程依然可以获取CPU,该进程可以在发起异步操作之后的接下来的任何时间做任何事,如果需要获取异步操作的结果,则应该去判断或等待新开的那个内核线程执行完毕(可以阻塞等待也可以轮询判断),当然,也可以不用去管异步操作的结果,这样内核线程操作完成的数据会一直留存在内存某处等待处理。