ChatGPT解决这个技术问题 Extra ChatGPT

如果我的界面必须返回 Task 什么是无操作实现的最佳方式?

在下面的代码中,由于接口的原因,类 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)

S
Servy

今天,我建议使用 Task.CompletedTask 来完成此操作。

.net 4.6 之前:

与使用无操作表达式创建 Task 相比,使用 Task.FromResult(0)Task.FromResult<object>(null) 会产生更少的开销。创建具有预定结果的 Task 时,不涉及调度开销。


如果您碰巧使用 github.com/StephenCleary/AsyncEx,它们会提供一个 TaskConstants 类来提供这些已完成的任务以及其他几个非常有用的任务(0 int、true/false、Default<T>())
return default(YourReturnType);
@Legends 这不适用于直接创建任务
我不确定,但 Task.CompletedTask 可能会成功! (但需要 .net 4.6)
C
Community

要向 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;。什么更可取(可能更有效或更一致)?
@Pixar 我不清楚。我的意思是“'no-async'会更有效”。使方法异步指示编译器将其转换为状态机。每次调用它时,它也会创建一个新任务。返回一个已经完成的任务会更清晰、更高效。
@Asad 它减少了分配(以及 GC 时间)。每次需要完成的任务时,无需分配新内存并构造任务实例,而只需执行一次。
J
Jon Hanna

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

从 4.6 开始,现在 Task.CompletedTask 的用途更加明确,但不仅 Task.Delay(0) 仍然返回单个缓存实例,它还返回与 Task.CompletedTask 一样的相同单个缓存实例。

两者的缓存性质都不能保证保持不变,但是作为依赖于实现的优化,它们只是依赖于实现的优化(也就是说,如果实现更改为仍然有效的东西,它们仍然可以正常工作)使用 { 1} 比公认的答案更好。


我仍在使用 4.5,当我进行一些研究时,我很高兴地发现 Task.Delay(0) 是返回静态 CompletedTask 成员的特殊情况。然后我将其缓存在我自己的静态 CompletedTask 成员中。 :P
我不知道为什么,但是 Task.CompletedTask 不能在 PCL 项目中使用,即使我将 .net 版本设置为 4.6(配置文件 7),刚刚在 VS2017 中测试。
@Fay我猜它一定不是PCL API表面的一部分,尽管目前唯一支持PCL的东西也支持4.5,所以我已经不得不使用我自己的Task.CompletedTask => Task.Delay(0);来支持它,所以我不确定我的头顶。
A
Alexander Trauzzi

最近遇到了这个问题,并且不断收到有关该方法无效的警告/错误。

我们的工作是安抚编译器,这可以清除它:

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

这汇集了迄今为止所有建议中最好的。除非您实际上在方法中做某事,否则不需要 return 语句。


那是完全错误的。您收到编译器错误,因为方法定义包含异步,因此编译器需要等待。 “正确”的用法是 public Task MyVoidAsyncMethog() { return Task.CompletedTask;}
不知道为什么这被否决了,因为这似乎是最干净的答案
因为基思的评论。
他并没有完全错,他只是删除了 async 关键字。我的方法更惯用。他是极简主义的。如果不是有点粗鲁。
这是没有意义的,在这里完全同意基思,我实际上并没有得到所有的支持。为什么要添加不必要的代码? public Task MyVoidAsyncMethod() {} 与上述方法完全相同。如果有这样使用它的用例,请添加附加代码。
X
Xin
return Task.CompletedTask; // this will make the compiler happy

return 对我不起作用 - 对于 async 任务,我只需要使用 await Task.CompletedTask
@dylanh724 我认为这取决于您的函数定义,原始问题需要返回一些东西,所以 return Task.CompletedTask 应该有所帮助。但是,如果您的函数定义概率返回 void,那么您可以 await
t
trashmaker_

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

Task.FromResult<MyClass>(null);

R
Remco te Wierik

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

    public async Task WillBeLongRunningAsyncInTheMajorityOfImplementations()
    {
    }

您会收到警告(CS1998 - 没有等待表达式的异步函数),但在这种情况下可以安全地忽略它。


如果您的方法返回 void,您可能会遇到异常问题。
K
Karthikeyan VK

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

            }

问题不在于异步方法:)
J
J.M.H
return await Task.FromResult(new MyClass());

虽然此代码可能会解决问题,但including an explanation如何以及为什么解决问题将真正有助于提高您的帖子质量,并可能导致更多的赞成票。请记住,您正在为将来的读者回答问题,而不仅仅是现在提出问题的人。请edit您的回答以添加解释并说明适用的限制和假设。