2010-07-29 164 views
9

几天前,我必须调查一个问题,即当我的应用程序显然处于空闲状态时,它显示的CPU使用率异常高。我将问题追踪到一个循环,该循环意图在套接字已设置为O_NONBLOCK时调用recvfrom调用,从而导致自旋锁定。解决此问题的方法有两种:将套接字设置为阻塞或使用pollselect轮询套接字上的可用数据。我选择了前者,因为它更简单。但我想知道为什么有人会创建一个非阻塞套接字,然后分别进行轮询。不是一个阻塞的套接字是不是一样的?有人会使用非阻塞套接字和轮询组合的用例是什么?在一般情况下它有什么优点吗?带轮询的非阻塞套接字

回答

7

使用poll()select()与非阻塞文件描述符为您提供了两个优点:

  • 您可以设置超时阻塞;
  • 您可以等待文件描述符集集合中的任何一个变为可用。

如果您只有一个文件描述符(套接字)需要等待,并且您不介意在其上无限期等待,那么是的;你可以使用阻塞呼叫。

第二个优势实际上是select()和朋友的杀手级用例。这意味着您可以处理多个套接字连接,以及标准输入和标准输出以及可能的文件I/O,所有这些都通过单个控制线程来完成。

1

导致自旋锁定。

这种情况通常称为紧密环

解决此问题的方法有两种:将套接字设置为阻塞或使用poll或select在套接字上轮询可用数据。我选择了前者,因为它更简单。

确定,其他的部分代码没有使用过poll()(或select()),并期望socket为非阻塞模式?

否则,是的,切换到阻塞模式是最简单的解决方案。

最佳向后兼容的解决方案将一直呼吁recvfrom()使用poll()等待插座成为可读的之前。这样可以确保代码的其他部分能够像以前一样精确地工作。

但我想知道为什么有人会创建一个非阻塞套接字,然后单独轮询它。不是一个阻塞的套接字是不是一样的?

对于recvfrom()的情况,我没有什么大的区别。

有人会使用非阻塞套接字和轮询组合的用例是什么?在一般情况下它有什么优点吗?

可能是一个简单的编码错误。或者有人可能会认为在紧缩环节中调整会以某种方式提高性能。

0

将套接字编号为nonblocking总是比较好,因为即使阻塞的套接字有时(即当数据到达但有校验和错误并且被丢弃时)也处于就绪状态 - 即使没有要读取的数据。因此,使它nonblocking,通过查询等待数据可用性然后读取。我认为这是主要优势。

1

我在这里发帖,因为虽然问题是旧的。它出现在我的谷歌搜索不知何故,并没有得到妥善回答。

接受的答案仅仅强调了使用非阻塞套接字的两个优点,但没有真正详细说明或回答实际问题。

  • 注:在非阻塞套接字不幸的是大多数在线“教程”或代码片段只拦截功能套接字代码,所以知识传播较少。

至于什么时候你会使用一个与另一个相比......一般情况下,阻塞套接字只用于在线代码片段。在所有(良好)生产应用中都使用非阻塞式插座。我不是无知的,如果你知道一个使用阻塞套接字的实现(并且确定这个套接字可以很好地与线程结合) - 或者让我们更具体的在单线程中使用阻塞套接字 - 请让我们我知道。

现在我可以给你一个很容易理解的例子,还有很多其他的例子。我们来看一个游戏服务器的例子。无论玩家是否提供输入(鼠标/键盘)来改变游戏状态,游戏都会在蜱中前进,游戏状态会持续一段时间。现在,当多人游戏中的套接字发挥作用时 - 如果您要使用阻塞套接字,除非玩家发送更新,否则游戏状态不会提前 - 因此,如果他们遇到互联网问题,游戏状态将永远不会持续更新并向所有玩家传播更改。你会有一个相当不稳定的经历。

现在使用非阻塞套接字,您可以在单线程上运行游戏服务器,更新游戏状态以及套接字,使用...让我们说50ms超时间隔 - 套接字数据只读来自连接的用户,当他们真正发送一些东西时,然后送入服务器模拟,处理并馈送到下一个打勾的游戏状态计算中。

+0

不要'select'和'poll'通过通知您某个特定操作**在您执行该操作时不会阻止**来缓解阻塞问题?这些优秀的生产应用程序是否仍禁用阻止? – TheBuzzSaw 2017-09-07 18:53:45

+0

@ TheBuzzSaw我不确定我是否理解这个问题。我们在这里排除了单个套接字的用法,所以你有一套你每次使用的文件描述符,它不是select,而是实际的recv调用块,等待数据被接收。 – 2017-09-07 20:08:10

+0

我在说,当一个程序使用'select'来复用十几个套接字时,通常没有必要将这些套接字放入非阻塞模式,因为调用'select'可以确定哪些动作不会被阻塞。如果'select'返回并告诉我'45'套接字不会阻塞读取,我可以调用'recv'而不用担心阻塞,对吧? – TheBuzzSaw 2017-09-07 22:10:24