知识卡片

多路复用I/O为何属于同步而非异步

普通读书笔记卡

内容

一个非常常见的认知误区,是把select/poll这类多路复用I/O当成异步操作——这个误区本身也曾出现在本节作者早年的文章里。误区的具体表现是这样类比的:去银行办业务需要排队时,通常会先取一个号码纸条,然后等银行叫号;把”银行叫号”理解成select操作,把手里的号码纸条比作向select注册的回调函数,一旦满足可操作的条件,就据此通知办理人去处理——按这个类比,多路复用操作看起来像是异步行为。但这个理解的根本错误在于:[[同步与异步的区别]]的关键从来不是”有没有用到回调机制”,而是”最终完成这件事的动作是不是要求办理者本人亲自去做”——所有需要本人亲自完成的操作都属于同步操作,不管中间是不是注册了一个回调(比如叫号小纸条)来等待通知,还是干脆自己从头到尾一直阻塞等着,两者在”同步/异步”这个维度上是一回事。回到银行例子:需要办业务的人可以拿着叫号小纸条边等边做别的事(比如刷手机),但一旦真正叫到号、可以办理业务了,办理者本人依然需要亲自去完成这次办理——这里必须区分两种不同的状态:一是”这件事现在是不是可以做了”(条件满足的通知,比如告诉你某个文件描述符可读了),二是”这件事到底有没有真正做完”(比如真正调用read/write完成了I/O操作本身)。多路复用I/O做的事情,只是记录下来”有哪些人在等待通知”、在条件满足时负责通知办理者,但真正把这件事做完,依然要靠办理者自己去完成——只要是自己去完成的操作,就都属于同步操作。这条判断也和POSIX标准的权威定义完全吻合:同步I/O操作会导致发起请求的进程被阻塞直到操作完成;异步I/O操作不会导致发起请求的进程被阻塞——按这个定义,阻塞I/O、非阻塞I/O、I/O多路复用、信号驱动I/O这四种模型全部属于同步(因为真正的I/O操作recvfrom本身都会阻塞进程),只有真正的异步I/O模型才符合异步的定义。

参考来源

- 位置:《高可用架构(第1卷)》第1章《高可用架构案例精选》"1.9 深入理解同步/异步与阻塞/非阻塞区别"节,"1.9.3 与多路复用I/O的联系"(源文件:_epub-src/OEBPS/Text/Chapter1_9_4.xhtml) - 结论依据:原文说明"上面这种理解的最大错误在于,同步与异步的区别在于是否要求办理者自己来完成,所有需要自己完成的操作都是同步操作……只要是自己去完成的操作,都是同步的操作",并引用POSIX定义"the first four I/O models—blocking, nonblocking, I/O multiplexing, and signal-driven I/O—are all synchronous because the actual I/O operation (recvfrom) blocks the process. Only the asynchronous I/O model matches the asynchronous I/O definition",直接支撑本卡片结论。 - 原始内容:上面这种理解的最大错误在于,同步与异步的区别在于是否要求办理者自己来完成,所有需要自己完成的操作都是同步操作,不管是注册了一个回调……等待回调你,还是自己一直阻塞等待……只要是自己去完成的操作,都是同步的操作。