Linux 和 I/O 完成端口?

Posted

技术标签:

【中文标题】Linux 和 I/O 完成端口?【英文标题】:Linux and I/O completion ports? 【发布时间】:2011-02-17 04:22:16 【问题描述】:

使用 winsock,您可以配置套接字或单独的 I/O 操作以“重叠”。这意味着执行 I/O 的调用会立即返回,而实际操作由单独的工作线程异步完成。

Winsock 还提供“完成端口”。据我了解,完成端口充当句柄(套接字)的多路复用器。如果句柄不在 I/O 操作的中间,即如果它的所有 I/O 操作都完成,则可以将其解复用。

那么,关于我的问题... linux 是否支持完成端口,甚至支持套接字的异步 I/O?

【问题讨论】:

epoll 是 Linux 最快的服务器编写方法。请注意,Linux 目前在 Internet 服务器市场上的份额比 Windows 更大。 @unixman83:我知道 epoll。我只是好奇,因为在 Linux 上提到了异步 I/O 支持,但我不完全确定是否特别支持套接字(BlackAura 证实了这一点)。附带说明一下,epoll 可能并非一直都是最好的解决方案(请参阅sheddingbikes.com/posts/1280829388.html)。 完成端口并不意味着多路复用套接字。它们对于单个套接字或文件句柄非常有用。它们是一种数据并行机制。它们的目的是允许多个线程处理从套接字或文件异步接收的数据。它们还用于线程池实现,例如 .NET。 【参考方案1】:

如果您正在寻找与 IOCP 完全相同的东西,您将找不到它,因为它不存在。

Windows 使用完成时通知模型(因此是 I/O 完成 端口)。您异步启动某些操作,并在该操作完成时收到通知。

Linux 应用程序(以及大多数其他类 Unix 应用程序)通常使用准备就绪模型的通知。您会收到一个通知,表明可以在不阻塞的情况下读取或写入套接字。然后,你做 I/O 操作,不会阻塞。

使用此模型,您不需要异步 I/O。数据会立即复制到套接字缓冲区中/从中复制出来。

这方面的编程模型有点棘手,这就是为什么有像 libevent 这样的抽象库的原因。它提供了一个更简单的编程模型,并抽象出支持的操作系统之间的实现差异。

Windows 中也有一个关于就绪模型的通知(select 或 WSAWaitForMultipleEvents),您可能以前看过。它无法扩展到大量套接字,因此不适合高性能网络应用程序。

不要让您失望 - Windows 和 Linux 是完全不同的操作系统。在一个系统上不能很好地扩展的东西可能在另一个系统上工作得很好。这种方法实际上在 Linux 上运行良好,性能与 Windows 上的 IOCP 相当。

【讨论】:

只要您写入的数据多于缓冲区可以容纳的数据,任何同步 I/O 都会阻塞。而且如果你正在写入的数据已经被page out,你的进程会在page fault时阻塞。 @BlackAura:WSAAsyncSelect 不支持在 Windows 上使用 notify-on-ready 模型的大量套接字吗?诚然,我没有将它与大量套接字一起使用,但是由于套接字句柄是作为事件参数传递的,并且没有要查询的位掩码或套接字数组,因此它似乎应该可以扩展。 @Ben Voigt WSAAsyncSelect 的问题在于它是围绕窗口过程 API 构建的。与其他轮询函数相比,它的消息循环很慢。必须处理数千个套接字会显着降低程序的性能。顺便说一句,“没有位掩码”是什么意思?你仍然需要传递标志。 @someguy:“无位掩码”是指不使用FD_SET,就像在选择中所做的那样。此外,WSAAsyncSelect 需要使用线程消息队列,而不是窗口过程 API。完全有可能在消息循环中捕获这些消息,而不是通过DispatchMessage 和窗口过程代码传递它们。 @Vladislav Vaintroub:WSARecv() 安排要执行的 I/O 操作。当操作完成时,GetQueuedCompletionStatus() 将返回。查看就绪事件和完成事件之间的区别。【参考方案2】:

IOCP 在各种 UNIX 平台上读作“异步 I/O”:

POSIX AIO 是标准 Kernel AIO、epoll 和 io_uring 似乎是特定于 Linux 的实现 Kqueue 是 *BSD 和 Mac OSX 的实现 Message Passing Interface (MPI) 是高性能计算的一个选项 强制升压参考 - Boost.Asio

【讨论】:

谢谢。您有机会向我提供一些示例代码吗?我之前研究过 POSIX AIO,但找不到任何与套接字相关的内容。 我之前没用过POSIX AIO。我只知道它已经在各个论坛上讨论过。就我个人而言,我运行基于 BSD 的系统,所以我为此使用了 Kqueue。如果这是您所追求的,我会考虑使用 Boost 或一些 MPI 实现来实现并发 I/O。 我研究了 POSIX AIO 和 Kernel AIO,两者似乎都暗示没有真正的套接字支持,这是一种耻辱。我假设我读过的所有文档都过时了,因为 Java 7 显然将支持异步 I/O,所以 linux 必须拥有它,或者将拥有它,对吧?也许我会尝试看看 Sun/Oracle 到目前为止所做的工作。 看起来 POSIX AIO 已经被冷落了。您可能想阅读有关 "Fast UNIX Servers" (dank.qemfd.net/dankwiki/index.php/Fast_UNIX_Servers) 的一些参考资料。那里似乎有很多很好的信息。 "异步 I/O" 有问题,并且在 大多数 Unices 上的支持很差!当心【参考方案3】:

使用 boost::asio。把手放下。它有一个温和的学习曲线,但它是跨平台的,并且会自动为您正在编译的系统使用最佳可用方法。根本没有理由不这样做。

我知道这不能完全回答您的问题,但这是我能给出的最佳建议。

【讨论】:

+1 我讨厌ASIO,因为它极端使用命名空间,但我不得不承认它是完全支持 Windows 和 Linux 的最高质量的免费库。另一方面,Libevent 对 Windows 的支持质量低劣、未完成。【参考方案4】:

那么,关于我的问题... linux 是否支持完成端口,甚至支持套接字的异步 I/O?

关于套接字,在 5.3 及更高版本的内核中,Linux has something analogous to completion ports in the shape of io_uring(对于文件/块设备io_uring 支持出现在 5.1 内核中)。

【讨论】:

【参考方案5】:

阅读谷歌libevent上的博文,可以在Unix上使用异步IO实现IOCP语义,但不能直接使用IOCP实现异步IO语义,

http://google-opensource.blogspot.com/2010/01/libevent-20x-like-libevent-14x-only.html

有关带有 BSD 套接字 API 的跨平台异步 IO 示例,请查看最近在 LWN.net 上发布的 ZeroMQ,

http://www.zeromq.org/

LWN 文章,

http://lwn.net/Articles/370307/

【讨论】:

我不认为 libevent 支持异步 I/O,它甚至在链接页面上说它是用于非阻塞套接字的。我想我以后会更深入地研究它。 0MQ 也很有趣,但我认为这不是我想要的。它似乎是一个消息传递库(类似于 erlang actor?) @someguy 异步 I/O 包含/包含非阻塞套接字。【参考方案6】:

Boost ASIO 使用 epoll(Reactor 模式)在 Linux 上实现 Windows 风格的 IOCP(Proactor 设计模式)。见http://think-async.com/Asio/asio-1.5.3/doc/asio/overview/core/async.html

【讨论】:

从提供的链接中引用和总结该页面可能更有用,因为链接腐烂会发生,用户将在某个时候单击它以找到 404。

以上是关于Linux 和 I/O 完成端口?的主要内容,如果未能解决你的问题,请参考以下文章

Windows系统编程之异步I/O和完成端口

用于小型单线程应用程序的 I/O 完成端口?

我的循环错了吗?我是不是滥用 ReadFile() 和 I/O 完成端口?

重叠 I/O:如何在完成端口事件或正常事件上唤醒线程?

I/O 完成端口,如何释放每个套接字上下文和每个 I/O 上下文?

测试 I/O 完成端口支持