17

我已经看到了一些select()poll()or进行比较的文章epoll(),并且我看到了许多指南讨论了select()多个套接字的实际用法。

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

4

3 回答 3

10

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

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

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

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

于 2013-10-03T21:29:52.123 回答
6

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

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

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

于 2013-10-03T22:05:48.113 回答
5

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

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

实际上,select()它会告诉您何时知道对套接字的下一次读取或写入操作成功,因此如果您仅在 select 允许时尝试读取和写入,即使您没有使套接字变为非-阻挡!select()这样做仍然是不明智的,因为尽管报告套接字“准备好”,但下一个操作仍然可能阻塞时存在边缘情况。

另一方面,由于@Troy 解释select()的原因,几乎不建议使套接字不阻塞且不使用。

于 2013-10-03T22:13:10.780 回答