【发布时间】:2013-05-26 12:33:41
【问题描述】:
我有一个方法 Limit(),它计算在特定时间内通过某个通道的带宽,并通过使用 Thread.Sleep() 来限制它(如果达到带宽限制)。 方法本身产生正确的(在我看来结果)但 Thread.Sleep 没有(由于多线程 CPU 使用),因为我有正确的“毫秒ToWait”,但之后的速度检查远非我通过的限制。
有没有办法让限制更精确?
限制器类
private readonly int m_maxSpeedInKbps;
public Limiter(int maxSpeedInKbps)
{
m_maxSpeedInKbps = maxSpeedInKbps;
}
public int Limit(DateTime startOfCycleDateTime, long writtenInBytes)
{
if (m_maxSpeedInKbps > 0)
{
double totalMilliseconds = DateTime.Now.Subtract(startOfCycleDateTime).TotalMilliseconds;
int currentSpeedInKbps = (int)((writtenInBytes / totalMilliseconds));
if (currentSpeedInKbps - m_maxSpeedInKbps > 0)
{
double delta = (double)currentSpeedInKbps / m_maxSpeedInKbps;
int millisecondsToWait = (int)((totalMilliseconds * delta) - totalMilliseconds);
if (millisecondsToWait > 0)
{
Thread.Sleep(millisecondsToWait);
return millisecondsToWait;
}
}
}
return 0;
}
在大增量中总是失败的测试类
[TestMethod]
public void ATest()
{
List<File> files = new List<File>();
for (int i = 0; i < 1; i++)
{
files.Add(new File(i + 1, 100));
}
const int maxSpeedInKbps = 1024; // 1MBps
Limiter limiter = new Limiter(maxSpeedInKbps);
DateTime startDateTime = DateTime.Now;
Parallel.ForEach(files, new ParallelOptions {MaxDegreeOfParallelism = 5}, file =>
{
DateTime currentFileStartTime = DateTime.Now;
Thread.Sleep(5);
limiter.Limit(currentFileStartTime, file.Blocks * Block.Size);
});
long roundOfWriteInKB = (files.Sum(i => i.Blocks.Count) * Block.Size) / 1024;
int currentSpeedInKbps = (int) (roundOfWriteInKB/DateTime.Now.Subtract(startDateTime).TotalMilliseconds*1000);
Assert.AreEqual(maxSpeedInKbps, currentSpeedInKbps, string.Format("maxSpeedInKbps {0} currentSpeedInKbps {1}", maxSpeedInKbps, currentSpeedInKbps));
}
【问题讨论】:
-
“远”到底是什么意思?你说的有多远?
-
您确定
Thread.Sleep会阻止更多数据进入通道吗?虽然确实你不会得到很多精确度,但我不相信这是你的问题。您多久拨打一次Limit? -
如果你的睡眠时间很短,那么实际的睡眠时间将不准确 - 线程时间片是 15 毫秒,因此将其加倍或三倍以获得合理准确度的最小增量。但是,您可以使用秒表来测量您的实际睡眠时间:msdn.microsoft.com/en-us/library/…
-
实际上在 Windows 7 及更高版本中,
Thread.Sleep()几乎可以精确到毫秒 - 但DateTime.Now肯定不是。 -
我明白了,这个问题并没有说明您正在发送。我盲目地假设您正在接收,似乎我错过了参数称为
writtenInBytes的事实。无论如何,对于超过 300 毫秒的延迟,我觉得Thread.Sleep应该足够准确,因为您多次调用Limit。与块的大小(50 kb,我相信你说)相比,总数据大小是多少?您是否愿意发布一个说明问题的小型可编译示例?另外,我支持@MatthewWatson,因为您应该使用Stopwatch而不是DateTime.Now。