If my interface must return Task what is the best way to have a no-operation implementation?
在下面的代码中,由于接口的原因,类LazyBar 必须从它的方法返回一个任务(为了参数,不能更改)。如果LazyBar 的实现是不寻常的,因为它恰好快速同步地运行——从该方法返回无操作任务的最佳方法是什么?
我已经使用下面的Task.Delay(0) ,但是我想知道,如果函数被大量调用,这是否有任何性能副作用(为了参数起见,每秒数百次):
这种句法上的甜言蜜语是否意味着一件大事?
它是否开始阻塞应用程序的线程池?
编译器解释器是否足以处理Delay(0) 不同的问题?
return Task.Run(() => { }); 有什么不同吗?
有更好的方法吗?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
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
( ) ;
}
}
}
相关问题:stackoverflow.com/questions/4245968/create-a-completed-task
就我个人而言,我会和Task.FromResult(null) 一起去。
使用Task.FromResult(0) 或Task.FromResult(null) 比使用no-op表达式创建Task 的开销要小。当创建一个结果预先确定的Task 时,不涉及调度开销。
今天,我建议您使用task.completedtask来完成此任务。
如果您碰巧使用github.com/stephencleary/asyncex,它们会提供一个taskconstants类来提供这些已完成的任务以及其他一些非常有用的任务(0 int,true/false,default())
return default(YourReturnType);
@无法直接创建任务的图例
我不确定,但江户十一〔一〕可能会耍花招!(但需要.NET 4.6)
@彼得,是的,那现在会更好。
问题:返回Task 的Task.FromResult 如何满足Task 的返回类型(无类型参数)?
如果我在async Task 方法中什么都不做(比如说不满足等待的条件),最终会同步运行吗?
为了增加Reed Copsey关于使用Task.FromResult 的回答,如果缓存已完成的任务,则可以提高性能,因为已完成任务的所有实例都是相同的:
1 2 3 4
public static class TaskExtensions
{
public static readonly Task CompletedTask = Task. FromResult ( false ) ;
}
使用TaskExtensions.CompletedTask ,您可以在整个应用程序域中使用相同的实例。
最新版本的.NET框架(v4.6)只添加了带有Task.CompletedTask 静态属性的内容。
1
Task completedTask = Task. CompletedTask ;
我需要退回还是等待?
@皮克斯,你什么意思?您可以同时执行这两项操作,但等待将同步进行。
不好意思,我不得不提一下上下文:)我现在看到了,我们可以做public Task WillBeLongRunningAsyncInTheMajorityOfImplementations() 和public async Task WillBeLongRunningAsyncInTheMajorityOfImplementations() 。所以,我们可以选择return CompletedTask; 或await CompletedTask; 。什么是更可取的(也许更有效或更一致)?
@pixar no async的效率会更高。不管怎样,如果您选择了异步,那么您就不需要一个完成的任务来开始(async Task DoAsync() { } )。
所以,这应该是乔恩问题的答案吗?
@皮克斯我不清楚。我的意思是"不异步"会更有效。使方法异步将指示编译器将其转换为状态机。它还将在每次调用时创建一个新任务。返回一个已经完成的任务将更清晰和更有效。
好吧,现在我明白了。非常感谢你!:)
出于好奇,缓存已解决的任务将如何影响性能?
@它减少了分配(以及使用它的GC时间)。每次需要一个已完成的任务时,您只需分配一次新内存和构造一个任务实例,而不必每次都分配一个新内存。
@i3arnon afaik Task.FromResult 已经缓存了所有内容。
@Alexzhukovskiy它不能也不能,这基本上是一个内存泄漏,因为它不知道它可能接收多少可能的值。为true 和false 缓存2个任务是可以的,但是为int 缓存40亿任务是很有问题的。
@i3提示尚未完成,但将实施。
@亚历克朱可夫斯基1。这是一个不同的API。Task.FromResult 仍不缓存。2。这是一个建议,并不意味着它会被执行。
@我3警告你没有读到第一条被否决的评论?
@我有亚历克朱可夫斯基。Task.FromResult 将缓存所有内容的可能性为零。它可能会缓存一些常见值,如true 、false 、0 和其他一些默认值。
@我明白你的意思了。如果缓存一些默认值就足够了。
最好调用此taskConstant,因为它将与system.threading.tasks.taskSextures冲突。
在接受的答案中,Task.Delay(0) 是一种很好的方法,因为它是已完成Task 的缓存副本。
从4.6开始,现在有了Task.CompletedTask ,目的更加明确,但Task.Delay(0) 不仅返回单个缓存实例,而且返回的单个缓存实例与Task.CompletedTask 相同。
两者的缓存性质都不能保证保持不变,但作为仅依赖于实现的依赖于实现的优化(即,如果实现更改为仍然有效的内容,它们仍然可以正常工作),使用Task.Delay(0) 比公认的答案更好。
我仍然在使用4.5,当我做一些研究时,我很高兴找到了那个任务。delay(0)是一个特殊的情况,返回一个静态完成的任务成员。然后缓存在自己的静态完成任务成员中。P
我不知道为什么,但是Task.CompletedTask 不能用于PCL项目,即使我将.NET版本设置为4.6(配置文件7),刚刚在VS2017中测试过。
@Fay我想这肯定不是PCL API表面的一部分,尽管目前唯一能做的事情就是支持PCL也支持4.5,所以我已经不得不用我自己的Task.CompletedTask => Task.Delay(0); 来支持它了,所以我不太清楚。
最近遇到此问题,并不断收到有关该方法无效的警告/错误。
我们的任务是安抚编译器,这就清楚了:
1 2 3 4
public async Task MyVoidAsyncMethod( )
{
await Task. CompletedTask ;
}
这就汇集了迄今为止最好的建议。除非您在方法中实际做了一些事情,否则不需要返回语句。
那是完全错误的。因为方法定义包含异步,所以您收到一个编译器错误,所以编译器需要等待。"正确"用法为public task myvoidAsyncMethog()return task.completedTask;
不知道为什么投了反对票,因为这似乎是最清楚的答案。
因为基思的评论。
他没有完全错,只是删除了async关键字。我的方法更惯用。他是个极简主义者。如果不是有点粗鲁。
这没有道理,完全同意基思的观点,我并没有得到所有的赞成票。为什么要添加不必要的代码?public Task MyVoidAsyncMethod() {} 与上述方法完全相同。如果有这样使用它的用例,请添加额外的代码。
我的用例是'public async task myvoidAsyncMethod()if!调试..dostuff…#endif等待task.completedtask;
以避免无效警告。除非他们已经更新了编译器来停止这样做。
我更喜欢.NET 4.6的Task completedTask = Task.CompletedTask; 解决方案,但另一种方法是将方法标记为Async并返回void:
1 2 3
public async Task WillBeLongRunningAsyncInTheMajorityOfImplementations( )
{
}
您将收到一个警告(CS1998-Async函数,不带await表达式),但在这个上下文中可以安全地忽略它。