【问题标题】:What it costs to use Task.Delay()?使用 Task.Delay() 的成本是多少?
【发布时间】:2013-06-27 01:03:23
【问题描述】:

我正在考虑在具有事件驱动逻辑的 MMO 游戏服务器中使用 C# async\await。让我们假设有数千个实体在做一些已知持续时间的工作。所以我想为我的每个游戏对象调用Time.Delay()。 (这是与普通无限循环相反的方法,每个游戏对象都有一些 Update() 调用。)

有人知道Task.Delay() 是如何实现的吗? 是否使用计时器?是否占用系统资源?

可以同时产生数千个Task.Delay() 调用吗?

【问题讨论】:

  • @ColeJohnson 因为Thread.Sleep 不是async
  • Task.Delay 是什么?那没有意义。如果我想延迟一个线程,我现在就想要它,而不是产生另一个线程来告诉一个停止。
  • @Cole 重点是让线程在恢复之前等待一段时间。重点不是延迟线程。
  • @ColeJohnson 等待/异步的东西会导致对Task.Delay() 的调用似乎立即从调用它的代码返回,并且延迟结束后的代码将在延迟结束后恢复。它是非阻塞的(只要调用它的方法本身是async)。
  • @It'sNotALie。因为使用 0 或 1 以外的参数调用 Thread.Sleep 总是一个很大的设计问题。

标签: c# multithreading asynchronous async-await


【解决方案1】:

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();
  }
}

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

【讨论】:

  • 我真的很惊讶它为每个延迟创建一个新的计时器对象。我原以为它会使用一个带有一个计时器的增量队列。
  • 正如 MSDN 文档中所说:“System.Threading.Timer 是一个简单的轻量级计时器,它使用回调方法并由线程池线程提供服务。”对我来说,“轻量级”和“线程池线程”似乎是不相容的概念。
  • 我相信实际(非托管)实现确实使用了增量队列。尽管如此,如果您有很多很多Delay 调用,您将创建大量垃圾,这不是最有效的解决方案。如果您的“数以千计的实体”每秒都在做几件事,我会考虑替代方案。
  • 我的意思是 System.Timers.Timer 实现,它是 CLR 的一部分。几年前查过之后,我要从记忆中消失了——我可能错了。
  • .NET 定时器实现包装了 Win32 定时器队列,这是一个在线程池上触发事件的增量队列。更多信息:msdn.microsoft.com/en-us/library/ms686796%28v=VS.85%29.aspx
猜你喜欢
  • 1970-01-01
  • 2012-05-13
  • 1970-01-01
  • 1970-01-01
  • 2010-11-15
  • 2010-09-16
  • 1970-01-01
  • 1970-01-01
  • 2010-09-10
相关资源
最近更新 更多