在下面的代码中,由于接口的原因,类 LazyBar
必须从其方法中返回一个任务(并且为了参数,不能更改)。如果 LazyBar
的实现不寻常,因为它碰巧快速同步地运行 - 从该方法返回 No-Operation 任务的最佳方式是什么?
我已经使用了下面的 Task.Delay(0)
,但是我想知道如果该函数被称为 lot 是否有任何性能副作用(为了论证,说每秒数百次):
这种句法糖会解开大事吗?
它是否开始阻塞我的应用程序的线程池?
编译器是否足以以不同的方式处理 Delay(0) ?
将返回 Task.Run(() => { });有什么不同吗?
有没有更好的办法?
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();
}
}
}
Task.FromResult<object>(null)
。
今天,我建议使用 Task.CompletedTask 来完成此操作。
.net 4.6 之前:
与使用无操作表达式创建 Task
相比,使用 Task.FromResult(0)
或 Task.FromResult<object>(null)
会产生更少的开销。创建具有预定结果的 Task
时,不涉及调度开销。
要向 Reed Copsey's answer 添加关于使用 Task.FromResult
的内容,如果您缓存已完成的任务,则可以进一步提高性能,因为已完成任务的所有实例都是相同的:
public static class TaskExtensions
{
public static readonly Task CompletedTask = Task.FromResult(false);
}
使用 TaskExtensions.CompletedTask
,您可以在整个应用程序域中使用相同的实例。
latest version of the .Net Framework (v4.6) 仅通过 Task.CompletedTask
静态属性添加
Task completedTask = Task.CompletedTask;
public Task WillBeLongRunningAsyncInTheMajorityOfImplementations()
和 public async Task WillBeLongRunningAsyncInTheMajorityOfImplementations()
。因此,我们可以选择 return CompletedTask;
或 await CompletedTask;
。什么更可取(可能更有效或更一致)?
接受的答案中的 Task.Delay(0)
是一种好方法,因为它是已完成 Task
的缓存副本。
从 4.6 开始,现在 Task.CompletedTask
的用途更加明确,但不仅 Task.Delay(0)
仍然返回单个缓存实例,它还返回与 Task.CompletedTask
一样的相同单个缓存实例。
两者的缓存性质都不能保证保持不变,但是作为依赖于实现的优化,它们只是依赖于实现的优化(也就是说,如果实现更改为仍然有效的东西,它们仍然可以正常工作)使用 { 1} 比公认的答案更好。
Task.CompletedTask
不能在 PCL 项目中使用,即使我将 .net 版本设置为 4.6(配置文件 7),刚刚在 VS2017 中测试。
Task.CompletedTask => Task.Delay(0);
来支持它,所以我不确定我的头顶。
最近遇到了这个问题,并且不断收到有关该方法无效的警告/错误。
我们的工作是安抚编译器,这可以清除它:
public async Task MyVoidAsyncMethod()
{
await Task.CompletedTask;
}
这汇集了迄今为止所有建议中最好的。除非您实际上在方法中做某事,否则不需要 return 语句。
public Task MyVoidAsyncMethod() {}
与上述方法完全相同。如果有这样使用它的用例,请添加附加代码。
return Task.CompletedTask; // this will make the compiler happy
return
对我不起作用 - 对于 async
任务,我只需要使用 await Task.CompletedTask
。
return Task.CompletedTask
应该有所帮助。但是,如果您的函数定义概率返回 void,那么您可以 await
当您必须返回指定类型时:
Task.FromResult<MyClass>(null);
我更喜欢 .Net 4.6 的 Task completedTask = Task.CompletedTask;
解决方案,但另一种方法是将方法标记为 async 并返回 void:
public async Task WillBeLongRunningAsyncInTheMajorityOfImplementations()
{
}
您会收到警告(CS1998 - 没有等待表达式的异步函数),但在这种情况下可以安全地忽略它。
如果您使用的是泛型,所有答案都会给我们编译错误。您可以使用 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);
}
}
return await Task.FromResult(new MyClass());
不定期副业成功案例分享
return default(YourReturnType);
Task.CompletedTask
可能会成功! (但需要 .net 4.6)