ProfK
ProfK

Reputation: 51094

Task.FromResult() vs. Task.Run()

I've come across quite a few situations lately where async methods execute synchronously, but return a Task anyway, so they can be awaited, e.g.

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

Surely it is better to dispatch the probably-long-running operation to a thread and return the still active task, to genuinely be awaited:

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

I some suspicion, though, that just spinning off TPL threads isn't the safest practice. Any commentary on these two different patterns?

Upvotes: 39

Views: 35066

Answers (2)

i3arnon
i3arnon

Reputation: 116636

If your method is synchronous you shouldn't return a Task to begin with. Just create a traditional synchronous method.

If for some reason that's not possible (for example, you implement some async interface) returning a completed task using Task.FromResult or even better in this case Task.CompletedTask (added in .NET 4.6) is much better than using Task.Run in the implementation:

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

If the consumer of your API cares strongly about the Task-returning method not running synchronously they can use Task.Run themselves to make sure.

You should keep in mind that async methods may have a considerable synchronous part (the part before the first await) even if they do eventually continue asynchronously. You can't assume async methods return a Task immediately anyway.

Upvotes: 40

vendettamit
vendettamit

Reputation: 14687

Task.FromResult doesn't actually creates or runs a task but it just wraps the returned result in a task object. I personally used it in Unit Tests where I need to simulate the Async methods and Of course I wouldn't want to run actual tasks in Unit tests.

Besides Task.Run will actually create a task and run a task on TaskScheduler. It is not recommended to use Task.Run when you're doing Async programming. Rather use await on tasks. See few do's and don't of Tasks by Stephen Cleary.

Upvotes: 28

Related Questions