IOCP和io_uring读写是否异步



据我所知。Linux epoll是异步通知。当文件描述符变得可读/可写/可接受时,epoll_wait将返回此fd。但读写仍然是同步的,会阻塞线程。因此Redis6.0使用线程池来处理网络io

Windows IOCP和Linux io_uring是Proactor。当io_uring_enter返回时,读取的数据已经放在缓冲区中,写入的缓冲区全部已经写入。

我的问题是:

  1. 谁负责复制这些缓冲区数据
  2. 读/写仍然阻塞当前线程吗
  3. 如果是,如何使用线程池加快速度

不确定半年后它是否仍然有用,但可能值得其他想知道相同问题的用户回答。

1.谁负责复制这些缓冲区数据

IOCP和io_uring都在操作系统内核端工作。在io_uring的情况下,内核生成执行任务并通过完成队列(CQ(发出完成信号的工作线程,这意味着您不仅可以避免自己调用read()write(),而且这些操作都是在内核中完成的,这样可以避免不必要的系统调用(用户/内核模式之间的上下文切换非常昂贵(。

您可以查看以下文章以更好地理解它:https://blog.cloudflare.com/missing-manuals-io_uring-worker-pool/

此外,您可以将io_uring视为系统调用的一种有效的批处理执行机制。它只允许以单个系统调用io_uring_enter的价格调用许多操作系统函数。

IOCP机制非常相似,尽管我无法找到它是如何准确地利用内核线程来执行任务的,但可以放心地假设它至少使用一个内核线程来处理其驱动程序IRP(I/O请求包(。

在回答您的问题时,内核及其内核模式线程负责复制缓冲区数据。

2.读/写是否仍然阻塞当前线程

如果将Overlapped I/O或io_uring与非阻塞文件/套接字一起使用,则提交给内核的调用不会阻塞当前线程。您只需要在等待(或轮询(完成队列时阻塞线程。


关于epoll和阻塞读写的一点补充:

对准备好的文件描述符的读取或写入并不是真正的"正常";"阻塞";您的线程,例如,如果套接字上有任何可用的数据,read()操作只会将其从内核缓冲区复制到您自己的缓冲区,仅此而已。除了付出系统调用的代价之外,没有真正的阻塞。但是,仍然可以使用线程池来并行化这些操作。您甚至可以为单个套接字并行读取,但这需要理解EPOLLONESHOTEPOLLEXCLUSIVE标志,以避免竞争条件和";雷鸣般的牛群;问题

这在本文中得到了很好的解释:https://idea.popcount.org/2017-02-20-epoll-is-fundamentally-broken-12/

最新更新