C# 如果我的接口必须返回 Task,那么实现无操作的最佳方法是什么?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13127177/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
If my interface must return Task what is the best way to have a no-operation implementation?
提问by Jon Rea
In the code below, due to the interface, the class LazyBarmust 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?
在下面的代码中,由于接口的原因,类LazyBar必须从它的方法中返回一个任务(并且不能更改参数)。如果LazyBars 的实现不寻常,因为它碰巧快速且同步地运行 - 从该方法返回 No-Operation 任务的最佳方法是什么?
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):
我已经使用了Task.Delay(0)下面的方法,但是我想知道如果函数被大量调用(为了参数,每秒说数百次),这是否有任何性能副作用:
- 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?
- 这个句法糖是否会解开一些大的东西?
- 它是否开始堵塞我的应用程序的线程池?
- 编译器是否足以以
Delay(0)不同的方式处理? - 请问
return Task.Run(() => { });有什么不同?
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();
}
}
}
采纳答案by Reed Copsey
Using Task.FromResult(0)or Task.FromResult<object>(null)will incur less overhead than creating a Taskwith a no-op expression. When creating a Taskwith a result pre-determined, there is no scheduling overhead involved.
与使用无操作表达式创建 a 相比,使用Task.FromResult(0)orTask.FromResult<object>(null)会产生更少的开销Task。创建Task具有预先确定的结果的a时,不涉及调度开销。
Today, I would recommend using Task.CompletedTaskto accomplish this.
今天,我会推荐使用Task.CompletedTask来完成这个。
回答by i3arnon
To add to Reed Copsey's answerabout 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:
要添加到Reed Copsey关于 using的回答中Task.FromResult,如果您缓存已完成的任务,您可以进一步提高性能,因为已完成任务的所有实例都是相同的:
public static class TaskExtensions
{
public static readonly Task CompletedTask = Task.FromResult(false);
}
With TaskExtensions.CompletedTaskyou can use the same instance throughout the entire app domain.
有了TaskExtensions.CompletedTask您可以使用相同的实例在整个应用程序域。
The latest version of the .Net Framework (v4.6)adds just that with the Task.CompletedTaskstatic property
在.Net框架(V4.6)的最新版本增加了这一点与Task.CompletedTask静态属性
Task completedTask = Task.CompletedTask;
回答by Jon Hanna
Task.Delay(0)as in the accepted answer was a good approach, as it is a cached copy of a completed Task.
Task.Delay(0)因为在接受的答案中是一个很好的方法,因为它是已完成的Task.
As of 4.6 there's now Task.CompletedTaskwhich is more explicit in its purpose, but not only does Task.Delay(0)still return a single cached instance, it returns the samesingle cached instance as does Task.CompletedTask.
从 4.6 开始,现在Task.CompletedTask它的目的更加明确,但不仅Task.Delay(0)仍然返回单个缓存实例,它还返回与相同的单个缓存实例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.
两者的缓存性质都不能保证保持不变,但是作为依赖于实现的优化,仅作为优化依赖于实现(也就是说,如果实现更改为仍然有效的东西,它们仍然可以正常工作)的使用Task.Delay(0)是比接受的答案更好。
回答by Remco te Wierik
I prefer the Task completedTask = Task.CompletedTask;solution of .Net 4.6, but another approach is to mark the method async and return void:
我更喜欢Task completedTask = Task.CompletedTask;.Net 4.6的解决方案,但另一种方法是将方法标记为 async 并返回 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.
您将收到警告(CS1998 - 没有 await 表达式的异步函数),但在这种情况下可以安全地忽略。
回答by Alexander Trauzzi
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.
这汇集了迄今为止最好的所有建议。除非您确实在该方法中执行某些操作,否则不需要 return 语句。
回答by trashmaker_
When you must return specified type:
当您必须返回指定类型时:
Task.FromResult<MyClass>(null);
回答by Xin
return Task.CompletedTask; // this will make the compiler happy
回答by Karthikeyan VK
If you are using generics, all answer will give us compile error. You can use return default(T);. Sample below to explain further.
如果您使用泛型,所有答案都会给我们编译错误。您可以使用return default(T);. 下面的示例以进一步解释。
public async Task<T> GetItemAsync<T>(string id)
{
try
{
var response = await this._container.ReadItemAsync<T>(id, new PartitionKey(id));
return response.Resource;
}
catch (CosmosException ex) when (ex.StatusCode == System.Net.HttpStatusCode.NotFound)
{
return default(T);
}
}

