2

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

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

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

所以作为一个测试,我把我的睡眠换成了

usleep(0);

我相信这应该可以让速度再次回到全速,但它仍然有限(仅达到最大速度的 1/20 左右)。所以我目前唯一的解释是,即使是 sleep(0),线程也会产生,因此没有线程获得足够的执行时间。

所以,对于冗长的解释感到抱歉,但是有没有更好的方法让我的线程休眠而不会造成这样的性能损失?

我已经尝试过,usleep 和 nanosleep 并且两者的结果相同。所有测试的设置相同,即线程数

系统:CentOS、pthreads、g++ 4.4.6

4

4 回答 4

2

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

于 2013-02-21T09:17:53.570 回答
1

很可能是函数调用本身减慢了速度(要么是因为函数调用的建立和拆除,要么是因为调用中的某些东西正在做其他让你慢下来的事情)。

您可能需要考虑如下一行:

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 个的点,但当然您可能仍然会发现处理不允许您达到全速。

于 2013-02-21T09:16:25.983 回答
0

您说“所以我目前唯一的解释是,即使对于 sleep(0),线程也会产生,因此没有线程获得足够的执行时间。”

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

你是否验证过usleep(0);真正引起问题,如果您注释掉这个电话,一切都按预期工作吗?

于 2013-02-21T09:34:06.707 回答
0

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

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

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

于 2013-02-21T09:45:49.937 回答