睡眠限制了线程性能

Sleep is limiting thread performance

本文关键字:线程 性能      更新时间:2023-10-16

我有一个多线程系统,其中有x数量的线程同时向网络发送数据包。

这一切都很好,但有些线程我想限制它们的速度,以便以一定的速率发送数据包。

因此,我在数据包注入循环中加入了睡眠,它很好地降低了线程的小速度(1Mbps到70Mbps左右),然而,如果我想将其限制在1Gbps,那么在睡眠到位的情况下,我就无法达到这个速度。现在我知道它可以达到这个速度,因为如果我从所有线程中去除睡眠,它们可以以每个接近2Gbps的速度注入。

因此,作为一项测试,我用代替了睡眠

usleep(0);

我认为这应该会使速度再次恢复到全速,但事实并非如此,它仍然受到限制(仅达到最大速度的1/20左右)。因此,我目前唯一的解释是,即使是睡眠(0),线程也会屈服,因此没有一个线程获得足够的执行时间。

所以,很抱歉有这么长的解释,但有没有更好的方法可以在不造成性能损失的情况下睡眠线程?

我试过了,usleep和nanosleep,两者的结果都一样。所有测试的设置相同,即线程数

系统:CentOS,pthreads,g++4.4.6

考虑在注入的每个n数据包中添加sleep调用,而不是简单地在每次迭代中添加。这样,就不会对注入的每个数据包都产生线程切换的惩罚,并且可以以相当细粒度的方式控制睡眠量。

很可能是函数调用本身放慢了速度(要么是因为函数调用的设置和删除,要么是因为调用中的某些东西正在做其他事情,这会减慢速度)。

你可能想考虑这样一行:

if (delay > 0) usleep (delay);

因此,如果不需要延迟,则函数根本不会被调用

您甚至可以将其封装为:

#define usleepIfNonZero(n) { if (n > 0) usleep (n); }

当然,通常的注意事项适用于宏参数(不要传递类似x++的内容,否则会发现它会增加两次)。


或者,只需保持一个数据包计数和一个用于计算的基本时间,并计算出平均速度。例如:

#define PACKETS_PER_SEC 25
baseTime = now() - 1; // prevent divide by zero later on 
packetCount = 0;
while (1) {
    sendPacket (nextPacket());
    packetCount++;
    secondCount = now() - baseTime;
    while (packetCount / secondCount > PACKETS_PER_SEC) {
        sleep (1);
        secondCount = now() - baseTime;
    }
}

这将自动收敛到每秒数据包数达到25的点,但当然,您可能会仍然发现处理无法达到全速。

你说"所以我目前唯一的解释是,即使是睡眠(0),线程也会屈服,因此没有一个线程得到足够的执行时间。"

根据http://pubs.opengroup.org/onlinepubs/7908799/xsh/usleep.html如果usleep(…)得到0,则它没有影响,因此,如果我们将其传递0,则不应该发生线程上下文切换!

您是否验证了usleep(0);真的造成了问题,如果你评论了这个电话,一切都如预期?

不要以这种方式依赖睡眠来进行节流。你不在实时系统上。

相反,在你想发送X数据/时间单位的地方发送X数据的突发,其中时间单位可能是毫秒或类似的东西。然后在发送每个突发后,计算出你需要睡多少时间才能达到你想要的平均带宽并睡那么多。不要对最后一次爆发进行计算,而是以高精度计时记录每次爆发的开始时间,并计算在更大的一组爆发上的摊销,比如最后100次爆发或类似的情况。通过这种方式,您可以平均上下文切换、系统调用、主发送循环之外的东西的任何开销,以及返回运行进程的延迟。

当您usleep(x)(x!=0)正在让步并将被添加到运行队列中的某个位置时,无法保证您在非实时系统上再次成为运行进程的速度有多快。因此,随着时间的推移,您必须摊销管理费用中的此类差异。