在非阻塞应用程序中旋转而不会吞噬CPU时间

时间:2011-04-13 05:38:00

标签: c++ linux spinning

我有一个UDP网络应用程序,它读取发送给它的数据包然后处理它们(相同的线程)。读取是非阻塞的,所以我没有使用poll或select。

收到的数据包按会话分组。

工作取决于是否正在进行会话。如果没有工作要做,即没有会话,或者没有要处理的数据包,那么我需要旋转。

我一直在看这里找到的混合算法: http://www.1024cores.net/home/lock-free-algorithms/tricks/spinning

一直在玩它。我被告知更多是忙碌的等待。您使用什么方法来防止不必要的处理和不必要的高CPU使用率?

编辑:

感谢所有的答案和评论。 我现在正在做以下事情。当谈到从网络上阅读时,我看看是否还有其他工作要做。如果有,那么我调用poll超时为零。然后,我尽可能多地读取数据包,并将它们放入内存队列进行处理。如果没有其他工作,那么我轮询无限期(即-1)。它似乎工作得很好,当事情繁忙时CPU只是很高,否则它会降到零。

3 个答案:

答案 0 :(得分:3)

如果你无事可做,你应该阻塞 - 如果不是在套接字本身上(即如果它是一个处理多个网络套接字或事件类型的事件循环),那么在发生某些事情时发出信号的门(设计取决于您的操作系统如何执行异步I / O)。

当您等待非常短时间(通常仅在内核模式下)时,您应该只进行旋转。

答案 1 :(得分:1)

由于您必须从套接字读取,因此您可以执行阻塞读取。如果没有数据包,你没有理由继续运行,对吧?

如果有多个套接字,则阻塞读取将不起作用,因此您需要pselect()来监视多个描述符。

我错过了一些明显的东西吗?

接收数据报后,您可能会进行一些长期处理。如果您使用非阻塞I / O的原因是为了避免在处理会话时忽略传入流量,那么在这种情况下,显而易见的事情是fork()会话。 (嗯,所以我仍然认为我必须遗漏一些东西......)

答案 2 :(得分:1)

您每秒处理多少个数据包?处理这些数据包需要多长时间?如果使用阻塞线程,您获得的平均CPU使用率是多少?

除非阻塞等待接近100%使用,否则从阻塞本身削减一些性能可能有所帮助,旋转不会改善,而是会恶化性能。通过旋转,您可以锁定一个无法运行其他代码的核心(可能包括为您提供工作的代码:即读取网络的内核代码并将数据包传递给您的应用程序),您可以在不执行任何工作的情况下刻录资源在所有......

请注意,当文章说编写阻塞代码比非阻塞旋转等待更难时,作者不是在谈论在系统中实现阻塞版本的操作,而是在线程必须等待的情况下在由其他线程触发的条件上(共享变量值高于/低于限制,标志被更改...)。

此外,如果检查条件的成本很高,那么旋转将导致循环的每次迭代的成本,并且这可能会超过检查一次并执行昂贵的成本等等。

请记住,旋转是活动等待,在不消耗处理器的情况下询问如何主动等待是没有意义的,因为主动等待方法意味着消耗处理器时间。 你可以做些什么来避免不必要的CPU使用?使用阻塞调用来获取下一个数据包。在读取UDP数据包的特定情况下,我怀疑两次调用非阻塞读取的处理时间并不比单次调用阻塞读取操作更昂贵。

再次考虑一开始的问题,可以归结为:阻塞被证明是瓶颈吗? *这是一个活跃等待实际上可以帮助的场景吗?*