当有数百个Task.Delay时,性能如何?

时间:2015-08-21 04:49:47

标签: c# .net timer async-await task-parallel-library

对于发送到服务器的每个调用,我按Task.Delay创建一个新的计时器来监视其超时。

让我们说会有数百个并发呼叫。因此,会有数百Task个计时器。

我想TPL的内部实现考虑了这个场合,所有的任务都依赖于相同的底层计时器?

我不太了解Task.Delay内部如何运作的机制。

2 个答案:

答案 0 :(得分:9)

Task.Delay使用内部System.Threading.Timer实施。该计时器类是单个本机计时器之上的包装器。要同步对该单个本地计时器的访问,在创建新计时器(以及更改现有计时器)时会有AppDomain级别锁定。您可以在reference source

中看到这一点
internal bool Change(uint dueTime, uint period)
{
    // ...
    lock (TimerQueue.Instance)
    {
        // ...
    }
    // ...
}

在大多数情况下,这很好,但是当你每秒创建相当数量的这些计时器时,你可能会对该锁定产生重大争议。实际知道的唯一方法是在真实环境中分析您的应用程序

我个人已经通过使用计时器创建了太多自我取消CancellationTokenSource来达到这一点(你可以在我的博客上看到我如何避免这种情况:Surprising Contention In System.Threading.Timer)。

Stephen Toub的这篇文章还提到Coalescing CancellationTokens from Timeouts提及:

  

"当然,总会出现推动性能界限的情况,我们最近看到了一些高吞吐量的案例,人们为每千人创建了一个这样的CancellationToken每秒进行数千次异步调用。这是很多TimerCancellationTokenSource个实例。"

答案 1 :(得分:1)

如果可以接受近似延迟,则可以选择将Task.Delay替换为HashedWheelTimer

代码示例。

HashedWheelTimer timer = new HashedWheelTimer();
await timer.Delay(1000);