问题
In the code below, due to the interface, the class LazyBar must return a task from it\'s method (and for arguments sake can\'t be changed). If LazyBars implementation is unusual in that it happens to run quickly and synchronously - what is the best way to return a No-Operation task from the method?
I have gone with Task.Delay(0) below, however I would like to know if this has any performance side-effects if the function is called a lot (for arguments sake, say hundreds of times a second):
- Does this syntactic sugar un-wind to something big?
- Does it start clogging up my application\'s thread pool?
- Is the compiler cleaver enough to deal with
Delay(0)differently? - Would
return Task.Run(() => { });be any different?
Is there a better way?
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();
}
}
}
回答1:
Using Task.FromResult(0) or Task.FromResult<object>(null) will incur less overhead than creating a Task with a no-op expression. When creating a Task with a result pre-determined, there is no scheduling overhead involved.
Today, I would recommend using Task.CompletedTask to accomplish this.
回答2:
To add to Reed Copsey's answer about using Task.FromResult, you can improve performance even more if you cache the already completed task since all instances of completed tasks are the same:
public static class TaskExtensions
{
public static readonly Task CompletedTask = Task.FromResult(false);
}
With TaskExtensions.CompletedTask you can use the same instance throughout the entire app domain.
The latest version of the .Net Framework (v4.6) adds just that with the Task.CompletedTask static property
Task completedTask = Task.CompletedTask;
回答3:
Task.Delay(0) as in the accepted answer was a good approach, as it is a cached copy of a completed Task.
As of 4.6 there's now Task.CompletedTask which is more explicit in its purpose, but not only does Task.Delay(0) still return a single cached instance, it returns the same single cached instance as does Task.CompletedTask.
The cached nature of neither is guaranteed to remain constant, but as implementation-dependent optimisations that are only implementation-dependent as optimisations (that is, they'd still work correctly if the implementation changed to something that was still valid) the use of Task.Delay(0) was better than the accepted answer.
回答4:
Recently encountered this and kept getting warnings/errors about the method being void.
We're in the business of placating the compiler and this clears it up:
public async Task MyVoidAsyncMethod()
{
await Task.CompletedTask;
}
This brings together the best of all the advice here so far. No return statement is necessary unless you're actually doing something in the method.
回答5:
return Task.CompletedTask; // this will make the compiler happy
回答6:
When you must return specified type:
Task.FromResult<MyClass>(null);
回答7:
I prefer the Task completedTask = Task.CompletedTask; solution of .Net 4.6, but another approach is to mark the method async and return void:
public async Task WillBeLongRunningAsyncInTheMajorityOfImplementations()
{
}
You'll get a warning (CS1998 - Async function without await expression), but this is safe to ignore in this context.
来源:https://stackoverflow.com/questions/13127177/if-my-interface-must-return-task-what-is-the-best-way-to-have-a-no-operation-imp