【问题标题】:Shall we use poll() or select()?我们应该使用 poll() 还是 select()?
【发布时间】:2011-12-08 22:09:24
【问题描述】:

我完全了解poll()select() 之间的主要区别:

  • select() 只支持固定数量的文件描述符
  • 据说更多系统支持select()
  • poll() 允许对事件类型进行更细粒度的控制
  • poll() 的实现可能在某些细节上有所不同

但是,它们都以大致相同的方式完成相同的任务。所以:

我们应该使用poll() 还是select()


编辑:我可能会补充一点,我对 epoll() 不感兴趣,因为我关心的是可移植性。此外,libev(ent) 也不是一个选项,因为我问这个问题是因为我正在为libev(ent) 编写自己的替换库。

【问题讨论】:

  • 答案可能是epoll()
  • epoll() 纯粹与 Linux 相关。我应该补充一点,我强调可移植性。
  • 你考虑过pselect吗?
  • @Philip:您可能应该将此添加到问题中,因为有大量 epoll 狂热者在不了解其局限性或实际有益的极端情况下四处推荐它。跨度>
  • 你为什么要自己替换 libev(ent)?

标签: c++ c networking network-programming posix


【解决方案1】:

所有远程现代系统都有poll,它几乎在所有方面都比select/pselect 更优越:

  • select 相比,poll 允许对状态进行更细粒度的检测。
  • poll 对您可以使用的最大文件描述符没有限制(更重要的是,当您无法检查超过 FD_SETSIZE 限制的文件描述符时,没有严重漏洞)。

我能想到的使用 poll 的唯一缺点是:

  • pselect 不同,poll 不能以原子方式取消屏蔽/屏蔽信号,因此您不能使用它来等待包含文件描述符活动和信号的一组事件,除非您使用自管道技巧。
  • poll 对于等待超时只有毫秒分辨率,而不是微秒 (select) 或纳秒 (pselect)。

poll 的可移植性当然不再是考虑因素。任何老到缺少poll 的系统都存在很多漏洞,因此不应该连接到网络。

总之,除非您有非常特殊的需求(微小的超时间隔、讨厌的信号交互、扩展到数百万个持久连接等),否则我会简单地使用 poll 并完成它。正如其他人所提到的,libevent 也是一种选择,但它不是干净/安全的代码(它对select 的使用实际上会调用危险的UB,试图解决select 的限制!)我发现使用@987654341 的代码@ 通常比直接使用 poll 的代码复杂得多。

【讨论】:

  • 我从未见过poll() 在 Windows 系统上可用。
  • 我也从未见过select 在 Windows 系统上可用,除非您指的是 winsock 中同名的损坏的不合格函数...
  • 它有什么不合规之处?除了它忽略第一个参数。
  • 在 Windows 下,select(0, NULL, NULL, NULL, &timeout) 将立即返回错误代码,而不是在 (timeout) 指定的时间段内休眠。同样在 Windows 下,异步 TCP connect() 尝试的失败将仅通过 FD_ISSET(sockfd, &exceptionSet) 报告,而在我见过的所有其他操作系统上,它通过 FD_ISSET(sockfd, &writeSet) 报告。当然可以解决这些差异,但这很烦人:)
  • Winsock 当然不符合 posix 标准,但如果需要,可以选择。还有民意调查(自Vista 或Vista SP 起)。见这里:msdn.microsoft.com/en-us/library/windows/desktop/…
【解决方案2】:

如果你正在为 GNU/Linux 编写,你应该看看 epoll(7)。

但对于大多数跨平台支持,您可以考虑使用 libevent。 http://libevent.org/

实际上,如果不了解您要执行的操作的具体细节,很难推荐单个轮询/选择实现。

【讨论】:

  • Pablo,您现在应该可以添加 cmets,因为您的声望点数已超过 50。请记住,仅在需要版主注意时才使用标志。
  • -1 用于推荐epoll。它不仅不可移植,而且在(非常常见的)情况下表现更差,因为每个修改操作都需要一个系统调用,并且运行时由系统调用。 epoll 在任何地方都相当有害,除非在具有持久连接的巨型服务器(数万或数十万个客户端)中。
【解决方案3】:

我实际上会推荐 boost::asio,然后您可以尝试这两种实现并进行测试,看看最适合您的设置。

【讨论】:

    【解决方案4】:

    我会使用 libev 或 libevent。这些库是跨平台的,并抽象出底层实现的细节(例如轮询、选择)。

    【讨论】:

      【解决方案5】:

      根据您的具体需求,我会推荐poll::boost::asio。我发现 libevent 有点麻烦,它里面有各种各样的东西,面向 C 和/或面向更高级别的协议处理。

      我不推荐select。我已经看到select 的实现以奇怪而奇怪的方式无形地失败,因为超出了描述符限制。你能做的最好的事情就是让它以一种明显的方式失败。也许您的应用程序不太可能出现这种情况,但我不会碰运气。

      如今poll 几乎在select 所在的任何地方都可用。关于它唯一不是的地方是 Windows。但是,恕我直言,如果您想要跨平台移植到该平台,您最好使用像 ::boost::asio 这样的漂亮包装器,它很好地包装了最有效的操作系统技术。

      【讨论】:

        【解决方案6】:

        Apple 的 poll() 在 TTY、IME 方面存在问题。因此,在考虑可移植性的情况下,select() 可能是更好的选择。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-12-25
          • 1970-01-01
          • 2017-05-16
          • 2016-12-05
          • 1970-01-01
          • 1970-01-01
          • 2022-06-14
          • 2018-10-21
          相关资源
          最近更新 更多