使用 Task.Delay() 的成本是多少?

问题描述 投票:0回答:2

我正在考虑在具有事件驱动逻辑的 MMO 游戏服务器中使用 C# 异步等待。让我们假设有数千个实体在已知持续时间内做一些工作。所以我想为我的每个游戏对象调用

Time.Delay()
。 (这是与普通无限循环相反的方法,每个游戏对象都有一些
Update()
调用。)

有人知道

Task.Delay()
是如何实现的吗? 它使用定时器吗?系统资源占用大吗?

是否可以同时产生数千个

Task.Delay()
调用?

c# multithreading asynchronous async-await
2个回答
24
投票

Task.Delay
实现如下:

public static Task Delay(int millisecondsDelay, CancellationToken cancellationToken)
{
  //error checking
  Task.DelayPromise delayPromise = new Task.DelayPromise(cancellationToken);
  if (cancellationToken.CanBeCanceled)
    delayPromise.Registration = cancellationToken.InternalRegisterWithoutEC((Action<object>) (state => ((Task.DelayPromise) state).Complete()), (object) delayPromise);
  if (millisecondsDelay != -1)
  {
    delayPromise.Timer = new Timer((TimerCallback) (state => ((Task.DelayPromise) state).Complete()), (object) delayPromise, millisecondsDelay, -1);
    delayPromise.Timer.KeepRootedWhileScheduled();
  }
  return (Task) delayPromise;
}

它肯定使用定时器。它们用于名为

DelayPromise
的类中。这是它的实现:

private sealed class DelayPromise : Task<VoidTaskResult>
{
  internal readonly CancellationToken Token;
  internal CancellationTokenRegistration Registration;
  internal Timer Timer;

  internal DelayPromise(CancellationToken token)
  {
    this.Token = token;
  }

  internal void Complete()
  {
    if (!(this.Token.IsCancellationRequested ? this.TrySetCanceled(this.Token) : this.TrySetResult(new VoidTaskResult())))
      return;
    if (this.Timer != null)
      this.Timer.Dispose();
    this.Registration.Dispose();
  }
}

它确实使用了计时器,但我似乎并不担心。计时器只是回调到 complete 方法,它所做的是检查它是否被取消,如果是则取消它,否则只返回一个结果。对我来说似乎很好。


0
投票

在 .NET Core 中,

Task.Delay
是通过
TimerQueue
实现的。它不会每次都创建一个新的
Timer
。从我从 源代码 中可以看出,它创建了 N 个“队列”,其中 N 是 CPU 内核的数量。然后它为每个队列使用 1(一)个本机非托管操作系统计时器。

这比 .NET Framework 方法更轻量级,但每次调用

Task.Delay
时仍然会执行大量代码。我希望有更好的方法。

附言只是为谷歌搜索者添加了一个更新的版本。

© www.soinside.com 2019 - 2024. All rights reserved.