几天前,我不得不调查我的应用程序在(显然)处于空闲状态时显示异常高CPU使用率的问题。我将问题跟踪到一个循环,这个循环意味着阻塞recvfrom
调用,同时套接字已设置为O_NONBLOCK
- 导致旋转锁定。有两种方法可以解决问题:使用poll
或select
将套接字设置为阻塞或轮询套接字上的可用数据。我选择前者因为它更简单。但我想知道为什么任何人会创建一个非阻塞套接字然后单独轮询它。阻塞套接字是否也这样做?使用非阻塞套接字和轮询组合的用例有哪些?在一般情况下它有什么优势吗?
答案 0 :(得分:7)
将poll()
或select()
与非阻塞文件描述符一起使用会带来两个好处:
如果你只有一个文件描述符(套接字)要等待,而你不介意无限期地等待它,那么是;你可以使用阻止电话。
第二个优势实际上是select()
和朋友的杀手级用例。这意味着您可以使用单个控制线程来处理多个套接字连接,标准输入和标准输出以及可能的文件I / O.
答案 1 :(得分:2)
我在这里发帖,因为虽然问题很老。它出现在我的谷歌搜索中,并且肯定没有得到正确回答。
接受的答案仅突出了使用非阻塞套接字的两个优点,但并未真正详细说明或回答实际问题。
关于何时使用一个与另一个相比...通常,阻塞套接字仅用于在线代码片段。在所有(良好)生产应用中,使用非阻塞套接字。我不是一无所知,如果你知道一个使用阻塞套接字的实现(并且确定这很可能与线程组合) - 或者让我们更具体一点,在单个线程中使用阻塞套接字 - 请让我们我知道。
现在我可以给你一个非常容易理解的例子,还有很多其他的例子。我们以游戏服务器为例。无论玩家是否提供输入(鼠标/键盘)来改变游戏状态,游戏都会在游戏状态进行的定期间隔内前进。现在当套接字在多人游戏中发挥作用时 - 如果你使用阻塞套接字,除非玩家发送更新,否则游戏状态不会发展 - 所以如果他们有互联网问题,游戏状态永远不会一直更新并传播给所有玩家的变化。你会有一个相当不稳定的经历。
现在使用非阻塞套接字,您可以在单线程上运行游戏服务器,更新游戏状态以及套接字,使用...假设50毫秒超时间隔 - 并且套接字数据仅从连接用户实际发送的东西,然后输入服务器模拟,处理并输入游戏状态计算下一个滴答。
答案 2 :(得分:1)
导致旋转锁定。
这种情况通常被称为紧密循环。
有两种方法可以解决问题:使用poll或select将套接字设置为阻塞或轮询套接字上的可用数据。我选择了前者,因为它更简单。
您确定其他代码部分尚未使用poll()
(或select()
)并期望套接字处于非阻塞模式吗?
否则,是的,切换到阻止模式是最简单的解决方案。
最佳向后兼容的解决方案在调用recvfrom()
之前使用poll()
等待套接字变得可读。这样可以确保代码的其他部分可以像以前一样精确地工作。
但我想知道为什么任何人会创建一个非阻塞套接字然后单独轮询它。阻塞套接字是否也这样做?
对于recvfrom()
的情况,我不知道有什么重大差异。
使用非阻塞套接字和轮询组合的用例有哪些?在一般情况下,它有什么优势吗?
可能是一个简单的编码错误。或者有人可能认为在紧密循环中重新调整会以某种方式提高性能。
答案 3 :(得分:0)
将套接字设置为nonblocking
总是更好,因为即使阻塞套接字有时会变为就绪状态(当数据到达但有校验和错误而被丢弃时) - 即使没有数据要读取。所以把它nonblocking
,等待通过民意调查获得数据,然后阅读。我认为这是主要优势。