【问题标题】:socket select ()versus non-block recv套接字选择()与非块接收
【发布时间】:2013-10-03 21:16:01
【问题描述】:

我看过一些比较 select()poll()epoll() 的文章,并且我看过许多指南讨论 select() 与多个套接字的实际用法。

但是,我似乎找不到与没有select() 的非阻塞recv() 调用进行比较。如果只有 1 个套接字可读取和 1 个套接字可写入,是否有任何理由使用 select() 调用? recv() 方法可以设置为在没有可用数据时不阻塞并返回错误 (WSAEWOULDBLOCK),那么当您没有其他要检查的套接字时为什么还要调用 select() 呢?非阻塞recv() 调用慢很多吗?

【问题讨论】:

  • 这可能是您实现的所有细节。你试过了吗?
  • 当没有数据要连续读取时,你会怎么做?永远循环?或者使用 select 或 poll 或 epoll ?不管是阻塞还是非阻塞,都需要以某种方式等待数据。
  • 是的,正如@Troy 所说,这样你就可以实现主动等待——这意味着当没有什么要读的时候,处理器不会留情。

标签: c sockets nonblocking recv posix-select


【解决方案1】:

当您轮询无限消耗 cpu 时间时,您不希望在没有其他方法的情况下对 recv 进行非阻塞调用来等待套接字上的数据。

如果您没有其他要检查的套接字并且在同一线程中没有其他事情可做,则对 read 的阻塞调用可能是最有效的解决方案。虽然在这种情况下,考虑到这种效率就像是过早的优化。

这些考虑因素只会随着套接字数量的增加而发挥作用。

只有在单个线程上处理多个套接字的情况下,非阻塞调用才会更快。

【讨论】:

  • 我从您的回复和下面的回复中得知循环 recv() 占用更多 CPU 资源,这让我怀疑循环中的 select() 实际上会挂起线程?这可能正是我想知道的区别。另外,如果这是真的,我怀疑它只会暂停一段时间,这会将 select 变成阻塞调用?了解这一点后,您将如何建议一个 2 个套接字线程(1 个用于输入,1 个用于输出),在该线程中您需要它们都以最大速度处理,但输出仅在队列中有新数据可用时才重要?
  • 不幸的是,我为读/写 select() 线程找到的所有示例都使用 timeval 来阻止 select(),这不是尽可能快地读写。您需要等待 select() 返回才能再次调用它。如果你给 select() 一个时间值为零,我认为这就是你的意思?与简单地使用非阻塞调用相比,在你的循环中给出一个零时间值是否仍然被认为对 CPU 更友好,因为你将以相同的速率调用它?
  • 这一切都在我的理解范围内,我相信我遇到了一些不同的事情。例如,我的队列中有需要写入的数据。我调用 select()。它很可能会在设置写标志的情况下返回,我调用 send(),一切都很愉快。现在我的写入队列中没有任何内容,但我仍然希望阅读。我再次在循环中调用 select 。它现在会阻塞,直到数据进入以供读取,但是我最终可能会收到更多希望在我的发送队列中发送的数据。不幸的是,我在 select() 超时或收到数据之前无法发送数据。
  • 有关更多背景信息:我的问题是我必须尽可能快地读取来自套接字的数据,并且当我的进程中有数据可用时,我需要尽可能快地写入.这是在一个线程上,它在不支持信号的机器上使用稍旧的库。我似乎拥有的最好的是选择和非阻塞调用。这就是我寻求建议的地方。
【解决方案2】:

如果没有可用数据,并且您使用非阻塞 IO,recv() 将立即返回。 那么程序应该怎么做呢?您需要循环调用recv(),直到数据可用 - 这几乎没有任何理由使用 CPU。

recv() 上旋转并以这种方式烧毁 CPU 是非常不可取的;您宁愿希望进程等到数据可用并被唤醒;这就是 select()/poll() 和类似的东西。

而且,为了不烧CPU而在循环中sleep()也不是一个好的解决方案。您会在处理过程中引入高延迟,因为一旦数据可用,程序将无法立即处理数据。

【讨论】:

    【解决方案3】:

    select() 和朋友让您设计工作流程,使一个套接字的缓慢不会妨碍您为另一个套接字提供服务的速度。想象一下,数据从接收套接字快速到达,您希望尽快接受它并存储在内存缓冲区中。但是发送套接字很慢。当您填满了操作系统的发送缓冲区并且send() 给了您 EWOULDBLOCK 时,您可以发出 select() 来等待接收和发送套接字。如果接收套接字上的新数据到达,或者释放一些缓冲区并且您可以向发送套接字写入更多数据,则select() 将失败,以先发生者为准。

    当然,select() 更现实的用例是当您有多个套接字要读取和/或写入时,或者当您必须在两个套接字之间双向传递数据时。

    事实上,select() 会告诉你下一次对套接字的读写操作何时成功,所以如果你只在 select 允许的情况下尝试读写,即使你没有,你的程序也几乎可以工作。 t 使套接字非阻塞!这样做仍然是不明智的,因为尽管select() 报告套接字“已准备好”,但仍存在下一个操作可能阻塞的边缘情况。

    另一方面,由于reason explained by @Troy,使套接字非阻塞且不使用select() 几乎是不可取的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-01-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多