Task.FromResult()与Task.Run()

时间:2015-11-30 18:24:54

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

我最近遇到过很多情况,其中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线程并不是最安全的做法。关于这两种不同模式的评论?

2 个答案:

答案 0 :(得分:14)

如果您的方法是同步的,则不应该首先返回Task。只需创建一个传统的同步方法。

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

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

如果您的API消费者非常关心Task - 返回方法未同步运行,则可以自行使用Task.Run确认。

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

答案 1 :(得分:9)

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

此外Task.Run实际上会创建一个任务并在TaskScheduler上运行任务。当您进行Task.Run编程时,建议不要使用Async。而是在任务上使用await。请参阅Stephen Cleary的do's and don't of Tasks