5

我正在使用 epoll/devpoll/kqueue/poll/select(包括 windows-select)为异步套接字 IO 设计事件循环。

我有两个执行选项,IO 操作:

非阻塞模式,在 EAGAIN 上轮询

  1. 将套接字设置为非阻塞模式。
  2. 读/写到套接字。
  3. 如果操作成功,则将完成通知发布到事件循环。
  4. 如果我得到 EAGAIN,请将套接字添加到“选择列表”并轮询套接字。

轮询方式:轮询后执行

  1. 将套接字添加到选择列表并轮询它。
  2. 等待通知它可读可写
  3. 读/写
  4. 将完成通知发布到成功的事件循环

在我看来,在正常模式下使用时首先需要更少的系统调用,尤其是写入套接字(缓冲区非常大)。此外,看起来有可能减少“选择”执行次数的开销,特别是当您没有像 epoll/devpoll/kqueue 那样可扩展的东西时,这很好。

问题:

  • 第二种方法有什么优点吗?
  • 在众多操作系统上对套接字/文件描述符进行非阻塞操作是否存在任何可移植性问题:Linux、FreeBSD、Solaris、MacOSX、Windows。

注意:请不要建议使用现有的 event-loop/socket-api 实现

4

3 回答 3

3

我不确定是否存在任何跨平台问题;最多您必须使用 Windows Sockets API,但结果相同。

否则,您似乎在任何一种情况下都在轮询(避免阻塞等待),所以这两种方法都很好。只要您不将自己置于阻塞的位置(例如,在没有数据时读取,在缓冲区已满时写入),这根本没有区别。

也许第一种方法更容易编码/理解;所以,就这样吧。

您可能有兴趣查看libev的文档和c10k 问题,了解有关该主题的有趣想法/方法。

于 2010-05-06T18:57:21.000 回答
2

第一个设计是Proactor 模式,第二个是Reactor 模式

反应器模式的一个优点是您可以设计您的 API,这样您就不必分配读取缓冲区,直到数据实际可供读取。这可以减少等待 I/O 时的内存使用量。

于 2010-05-10T14:03:37.237 回答
1

根据我对低延迟套接字应用程序的经验:

写入 - 尝试从写入线程直接写入套接字(您需要为此获取事件循环互斥体),如果写入不完整,请订阅使用事件循环(select/waitformultipleobjects)准备写入,并在套接字获取时从事件循环线程写入可写

用于读取 - 始终“订阅”所有套接字的就绪状态,因此当套接字变得可读时,您总是从事件循环线程中读取

于 2010-05-10T14:30:41.457 回答