在下面的代码中,由于接口的原因,类LazyBar必须从它的方法返回一个任务(出于参数的考虑,不能更改)。如果LazyBars的实现是不寻常的,因为它恰好快速和同步地运行——从方法中返回一个No-Operation任务的最佳方法是什么?

我已经使用下面的Task.Delay(0),但是我想知道如果函数被大量调用(为了论证,说每秒数百次),这是否有任何性能副作用:

这个语法上的糖会不会变成一个大问题? 它是否开始阻塞应用程序的线程池? 编译器是否足以处理不同的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。完成这个任务。


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


最新版本的. net Framework (v4.6)在Task中添加了这一点。CompletedTask静态属性

Task completedTask = Task.CompletedTask;

delay(0)是一个很好的方法,因为它是一个已完成任务的缓存副本。

从4.6开始,现在有了Task。CompletedTask的目的更明确,但Task.Delay(0)不仅返回单个缓存实例,它还返回与Task.CompletedTask相同的单个缓存实例。

两者的缓存性质都不能保证保持不变,但作为依赖于实现的优化(也就是说,如果实现更改为仍然有效的内容,它们仍然可以正确工作),使用Task.Delay(0)比接受的答案更好。


我更喜欢Task completedTask = Task. completedTask;.Net 4.6的解决方案,但另一种方法是将方法标记为async并返回void:

    public async Task WillBeLongRunningAsyncInTheMajorityOfImplementations()
    {
    }

您将得到一个警告(CS1998 - Async函数没有await表达式),但在此上下文中忽略该警告是安全的。


最近遇到了这个问题,并不断得到关于方法为空的警告/错误。

我们的工作是安抚编译器,这就澄清了问题:

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

这是到目前为止最好的建议。没有return语句是必要的,除非你真的在方法中做一些事情。


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

Task.FromResult<MyClass>(null);

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

如果你使用泛型,所有答案都会给我们编译错误。你可以使用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());