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

26,878

Solution 1

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.

Solution 2

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.

Share:
26,878
ProfK
Author by

ProfK

I am a software developer in Johannesburg, South Africa. I specialise in C# and ASP.NET, with SQL Server. I have, in some way or another, been involved in software development for about eighteen years, but always learning something new. At the moment that is WPF and MVVM.

Updated on December 01, 2020

Comments

  • ProfK
    ProfK over 3 years

    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?