Reputation: 51094
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
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
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