如果我的界面必须返回任务,那么最好的方法是实现无操作的最佳方法



在下面的代码中,由于接口,LazyBar类必须从其方法返回任务(出于参数的缘故,无法更改)。如果LazyBar S实现不寻常,因为它恰好可以快速,同步运行 - 从该方法返回无操作任务的最佳方法是什么?

我已经使用了下面的Task.Delay(0),但是我想知道是否具有任何性能副作用,如果该函数称为a lot (出于论点的缘故,说数百次,一秒钟):

  • 这种句法糖对大的东西
  • 它是否开始堵塞我的应用程序的线程池?
  • 编译器的剪裂刀足以应对Delay(0)
  • return 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.pletedTask来完成此操作。


pre .net 4.6:

使用Task.FromResult(0)Task.FromResult<object>(null)比创建具有NO-OP表达式的Task的开销要少。当创建具有预定结果的Task时,不涉及开销。

要添加到Reed Copsey关于使用Task.FromResult的答案中,如果您缓存已经完成的任务,则可以进一步提高性能,因为所有完成任务的实例都是相同的:

public static class TaskExtensions
{
    public static readonly Task CompletedTask = Task.FromResult(false);
}

使用TaskExtensions.CompletedTask,您可以在整个应用程序域中使用相同的实例。


最新版本的.NET框架(v4.6)添加了Task.CompletedTask静态属性

Task completedTask = Task.CompletedTask;

Task.Delay(0)中的答案是一种很好的方法,因为它是完整的Task的缓存副本。

从4.6开始,现在有Task.CompletedTask在其目的上更加明确,但是Task.Delay(0)仍然返回一个缓存的实例,还返回相同的Task.CompletedTask。>

保证的缓存性质都保证保持恒定,而作为实现依赖性优化,仅是实现依赖于优化的优化(也就是说,如果实现更改为仍然有效的事物,它们仍然可以正常工作)使用Task.Delay(0)比接受的答案更好。

return Task.CompletedTask; // this will make the compiler happy

最近遇到了这一点,并继续获取有关该方法无效的警告/错误。

我们从事安装编译器的业务,这清除了:

    public async Task MyVoidAsyncMethod()
    {
        await Task.CompletedTask;
    }

这将到目前为止的所有建议中最好。除非您实际在方法中做某事,否则无需返回语句。

当您必须返回指定类型时:

Task.FromResult<MyClass>(null);

我更喜欢.net 4.6的Task completedTask = Task.CompletedTask;解决方案,但另一种方法是标记方法异步并返回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());

最新更新