这里是我能做的最简单的重现来说明这个问题。这是一个控制台应用程序,它创建一个有界的
BlockingCollection<int>
,启动一个后台线程,使用 TryTake
消耗集合中的项目,然后在主线程上循环使用 Add
项目,直到达到上限,如下所示:
// Measure the time it takes to add items to the collection with one millisecond delay between Adds.
var sw = Stopwatch.StartNew();
for (int i = 0; i < collection.BoundedCapacity; i++)
{
collection.Add(i);
await Task.Delay(millisecondsDelay: 1);
}
sw.Stop();
BoundedCapacity 为 1000 个项目,因此 for 循环花费的时间不应超过一秒。但是,正如示例代码中的注释所解释的那样,经过的时间始终大于最大预期时间(设置为 2 * BoundedCapacity 毫秒) - 在调试器下的我的机器上,时间在 3.2 范围内 - 4秒,而当运行没有调试器时,时间在15 - 16秒范围内!
当您注释掉行
await Task.Delay(millisecondsDelay: 1)
时,程序将按预期运行(循环将在几毫秒内完成)。
我不知道这里发生了什么。有人可以解释一下这种行为吗?
我的猜测是这与操作系统调度有关。
从 文档 您可以了解到 Windows 上的最低分辨率窗口是 15 毫秒:
此方法取决于系统时钟。这意味着,如果 millisecondsDelay 参数小于系统时钟的分辨率(在 Windows 系统上约为 15 毫秒),则时间延迟将近似等于系统时钟的分辨率。
意味着对
Delay(1)
的 1000 次调用应该大约需要 15s
而不是 1s