如果我的接口必须返回Task,那么实现无操作的最佳方法是什么?

本文翻译自:If my interface must return Task what is the best way to have a no-operation implementation?

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). 在下面的代码中,由于接口,类LazyBar必须从它的方法返回一个任务(并且为了参数而不能更改)。 If LazyBar s 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的实现很不寻常,因为它恰好快速且同步地运行 - 从该方法返回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? 编译器切割器是否足以以不同方式处理Delay(0)
  • Would return Task.Run(() => { }); 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楼

参考:https://stackoom.com/question/t4yf/如果我的接口必须返回Task-那么实现无操作的最佳方法是什么


#2楼

Using Task.FromResult(0) or Task.FromResult<object>(null) will incur less overhead than creating a Task with a no-op expression. 使用Task.FromResult(0)Task.FromResult<object>(null)将比使用no-op表达式创建Task产生更少的开销。 When creating a Task with a result pre-determined, there is no scheduling overhead involved. 在创建具有预先确定结果的Task时,不会涉及调度开销。


Today, I would recommend using Task.CompletedTask to accomplish this. 今天,我建议使用Task.CompletedTask来实现这一目标。


#3楼

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: 要添加Reed Copsey关于使用Task.FromResult 的答案 ,如果缓存已完成的任务,则可以进一步提高性能,因为已完成任务的所有实例都相同:

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. 使用TaskExtensions.CompletedTask您可以在整个应用程序域中使用相同的实例。


The latest version of the .Net Framework (v4.6) adds just that with the Task.CompletedTask static property 最新版本的.Net Framework(v4.6)只增加了Task.CompletedTask静态属性

Task completedTask = Task.CompletedTask;

#4楼

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.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 . 从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)比接受的答案好。


#5楼

I prefer the Task completedTask = Task.CompletedTask; 我更喜欢Task completedTask = Task.CompletedTask; solution of .Net 4.6, but another approach is to mark the method async and return void: .Net 4.6的解决方案,但另一种方法是将方法标记为异步并返回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 - 没有等待表达式的异步函数),但在此上下文中可以安全地忽略。


#6楼

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. 除非您实际在该方法中执行某些操作,否则不需要返回语句。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值