Problem
The class LazyBar in the code below must return a task from its method due to the interface (and can’t be modified for the sake of argument). What is the best way to return a No-Operation task from the method if the LazyBars implementation is special in that it runs swiftly and synchronously?
I chose Task.Delay(0) below, but I’m curious whether there are any performance implications if the function is called frequently (for example, hundreds of times per second):
Is there a better way to do things?
using System.Threading.Tasks;
namespace MyAsyncTest
{
internal interface IFooFace
{
Task WillBeLongRunningAsyncInTheMajorityOfImplementations();
}
/// <summary>
/// An implementation, that unlike most cases, will not have a long-running
/// operation in 'WillBeLongRunningAsyncInTheMajorityOfImplementations'
/// </summary>
internal class LazyBar : IFooFace
{
#region IFooFace Members
public Task WillBeLongRunningAsyncInTheMajorityOfImplementations()
{
// First, do something really quick
var x = 1;
// Can't return 'null' here! Does 'Task.Delay(0)' have any performance considerations?
// Is it a real no-op, or if I call this a lot, will it adversely affect the
// underlying thread-pool? Better way?
return Task.Delay(0);
// Any different?
// return Task.Run(() => { });
// If my task returned something, I would do:
// return Task.FromResult<int>(12345);
}
#endregion
}
internal class Program
{
private static void Main(string[] args)
{
Test();
}
private static async void Test()
{
IFooFace foo = FactoryCreate();
await foo.WillBeLongRunningAsyncInTheMajorityOfImplementations();
return;
}
private static IFooFace FactoryCreate()
{
return new LazyBar();
}
}
}
Asked by Jon Rea
Solution #1
Today, I would advise you to use Task. This task has been completed.
Pre .net 4.6:
Using the Task Task or FromResult(0). When compared to generating a Task with a no-op expression, FromResultobject>(null) has less overhead. There is no scheduling overhead when creating a Task with a pre-determined result.
Answered by Reed Copsey
Solution #2
I’d like to add to Reed Copsey’s response concerning Task. Because all instances of finished jobs are the same, you can increase efficiency even further by caching the already completed task:
public static class TaskExtensions
{
public static readonly Task CompletedTask = Task.FromResult(false);
}
You can utilize the same instance of TaskExtensions.CompletedTask across the whole app domain with TaskExtensions.CompletedTask.
The Task in the newest version of the.Net Framework (v4.6) does just that. completedTask is a static property that is set to true after a task is completed.
Task completedTask = Task.CompletedTask;
Answered by i3arnon
Solution #3
Task. Because it is a cached duplicate of a completed Task, Delay(0), as in the acceptable response, was a good approach.
Task is now available in version 4.6. Not only does Task, but also CompletedTask, which is more obvious in its goal. Delay(0) still return a single cached instance, it returns the same single cached instance as does Task. CompletedTask.
The use of Task is just implementation-dependent as optimizations (i.e., it would still operate correctly if the implementation changed to something still valid). The approved answer was better than Delay(0).
Answered by Jon Hanna
Solution #4
I came across this recently and started receiving warnings/errors about the function being void.
We’re here to appease the compiler, and this clarifies things:
public async Task MyVoidAsyncMethod()
{
await Task.CompletedTask;
}
This combines the best of all of the previous suggestions. Unless you’re actually performing something in the method, there’s no need for a return statement.
Answered by Alexander Trauzzi
Solution #5
return Task.CompletedTask; // this will make the compiler happy
Answered by Xin
Post is based on https://stackoverflow.com/questions/13127177/if-my-interface-must-return-task-what-is-the-best-way-to-have-a-no-operation-imp