【问题标题】:Task.FromResult() vs. Task.Run()Task.FromResult() 与 Task.Run()
【发布时间】:2016-03-04 11:45:33
【问题描述】:

我最近遇到了很多async 方法同步执行,但无论如何都返回一个任务,因此可以等待它们的情况,例如

public virtual Task CreateAsync(TUser user)
{
    ThrowIfDisposed();
    if (user == null) throw new ArgumentNullException("user");
    Context.Save(user);
    Context.Flush();
    return Task.FromResult(0);
}

当然最好将可能长时间运行的操作分派给一个线程并返回仍处于活动状态的任务,以便真正等待:

public virtual Task CreateAsync(TUser user)
{
    ThrowIfDisposed();
    if (user == null) throw new ArgumentNullException("user");
    return Task.Run(() =>
    {
        Context.Save(user);
        Context.Flush();
    });
}

不过,我有些怀疑,只是分离 TPL 线程并不是最安全的做法。对这两种不同的模式有何评论?

【问题讨论】:

  • 如果可能,您应该调用实际的异步方法,而不是其中任何一个。
  • @SLaks 第二个是不是异步的(除了不使用新关键字)? (来自不经常使用异步功能的人)
  • @SLaks 好的,我明白你在说什么。最好await Context.Save(user) 并从那里开始。如果我们假设 Context.Save 是 3rd-party 并且我们不能在那里添加异步,我们的选择是什么?似乎在 OP 中给出的选项之外,阻塞当前线程的第一个比第二个差得多,后者至少将其分流到另一个线程并允许当前线程继续?

标签: c# multithreading asynchronous async-await task-parallel-library


【解决方案1】:

如果您的方法是同步的,则不应返回 Task 开头。只需创建一个传统的同步方法即可。

如果由于某种原因这是不可能的(例如,您实现了一些异步接口)使用 Task.FromResult 或者在这种情况下甚至更好 Task.CompletedTask(在 .NET 4.6 中添加)返回完成的任务比使用 @ 好得多987654324@在实现中:

public virtual Task CreateAsync(TUser user)
{
    // ...
    return Task.CompletedTask;
}

如果您的 API 的使用者非常关心 Task-returning 方法没有同步运行,他们可以自己使用 Task.Run 来确保。

您应该记住,异步方法可能有相当多的同步部分(第一次等待之前的部分),即使它们最终会异步继续。 无论如何,您不能假设异步方法立即返回 Task

【讨论】:

    【解决方案2】:

    Task.FromResult 实际上并不创建或运行任务,它只是将返回的结果包装在任务对象中。我个人在Unit Tests 中使用它,我需要模拟Async 方法,当然我不想在单元测试中运行实际任务。

    除了Task.Run 之外,实际上会创建一个任务并在TaskScheduler 上运行一个任务。在进行Async 编程时,不建议使用Task.Run。而是在任务上使用await。见很少do's and don't of Tasks 斯蒂芬·克利里。

    【讨论】:

      猜你喜欢
      • 2023-03-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-18
      • 2015-01-09
      • 2013-10-06
      • 1970-01-01
      相关资源
      最近更新 更多