问答中心分类: C#如果我的接口必须返回任务,那么实现无操作的最佳方法是什么?
0
匿名用户 提问 5天 前

在下面的代码中,由于接口,类LazyBar必须从其方法返回任务(并且为了参数起见,不能更改)。如果LazyBar的实现是不寻常的,因为它碰巧快速且同步地运行-从方法返回无操作任务的最佳方法是什么?
我和Task.Delay(0)但是,我想知道如果函数被称为大量(为了论证,一秒钟说几百遍):

  • 这句句法上的甜言蜜语是否意味着什么大事?
  • 它是否开始阻塞我的应用程序的线程池?
  • 编译器解理器是否足以处理Delay(0)不同地
  • return Task.Run(() => { });有什么不同吗?

有更好的方法吗?

using System.Threading.Tasks;

namespace MyAsyncTest
{
    internal interface IFooFace
    {
        Task WillBeLongRunningAsyncInTheMajorityOfImplementations();
    }

    /// 
    /// An implementation, that unlike most cases, will not have a long-running
    /// operation in 'WillBeLongRunningAsyncInTheMajorityOfImplementations'
    /// 
    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(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();
        }
    }
}
8 Answers
0
i3arnon 回答 5天 前

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

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

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

这个的最新版本。Net Framework(v4.6)添加了Task.CompletedTask静态属性

Task completedTask = Task.CompletedTask;
Egor Okhterov 回复 5天 前

我需要吗returnit或等候在上面?

i3arnon 回复 5天 前

@皮克斯你什么意思?您可以同时执行这两项操作,但等待操作将同步进行。

Egor Okhterov 回复 5天 前

抱歉,我不得不提到上下文:)我现在看到,我们可以public Task WillBeLongRunningAsyncInTheMajorityOfImplementations()以及public async Task WillBeLongRunningAsyncInTheMajorityOfImplementations(). 所以,我们可以return CompletedTask;await CompletedTask;. 什么更可取(可能更有效或更一致)?

i3arnon 回复 5天 前

@Pixar no async将更加高效。不管怎样,如果您确实选择了异步,那么您就不需要一个已完成的任务来开始(async Task DoAsync() { });

Egor Okhterov 回复 5天 前

那么,这应该是Jon问题的答案?

i3arnon 回复 5天 前

@皮克斯,我不清楚。我的意思是“no-async”会更有效率”。使方法异步将指示编译器将其转换为状态机。每次调用它时,它还会创建一个新任务。返回一个已经完成的任务会更清晰、更高效。

Asad Saeeduddin 回复 5天 前

出于好奇,缓存已解决的任务会如何影响性能?

i3arnon 回复 5天 前

@它减少了分配(以及GC时间)。每次需要完成任务时,您只需执行一次,而不是分配新内存和构造任务实例。

i3arnon 回复 5天 前

@亚历克斯·朱科夫斯基事实并非如此它不能,这将基本上是一个内存泄漏,因为它不知道它可以接收多少可能的值。缓存的2个任务truefalse很好,但缓存40亿int这是很有问题的。

Alex Zhukovskiy 回复 5天 前

@i3arnon还没有完成,但是它将得到实施.

i3arnon 回复 5天 前

@亚历克斯·朱科夫斯基1。这是一个不同的API。Task.FromResult仍不会缓存。2、这是一个建议,并不意味着它会得到实施。

i3arnon 回复 5天 前

@亚历克斯·朱科夫斯基我有。没有任何机会Task.FromResult将缓存所有内容。会的大概缓存一些常见值,如true,false,0以及其他一些默认值。

arviman 回复 5天 前

最好调用此TaskConstant,因为它会与系统冲突。穿线。任务。任务性紧张。

0
Jon Hanna 回答 5天 前

Task.Delay(0)在公认的答案中,这是一种很好的方法,因为它是已完成的Task.
从4.6开始Task.CompletedTask其目的更加明确,但不仅如此Task.Delay(0)仍然返回单个缓存实例,它将返回相同的单个缓存实例Task.CompletedTask.
两者的缓存性质都不能保证保持不变,但作为依赖于实现的优化,它只依赖于实现的优化(也就是说,如果实现更改为仍然有效的内容,它们仍然可以正常工作)Task.Delay(0)比公认的答案要好。

Darren Clark 回复 5天 前

我仍然在使用4.5,当我做一些研究时,我发现这个任务很有趣。延迟(0)是返回静态CompletedTask成员的特殊情况。然后将其缓存在自己的静态CompletedTask成员中:P

Felix 回复 5天 前

我不知道为什么,但是Task.CompletedTask无法在PCL项目中使用,即使我设置了。net版本到4.6(概要文件7),刚刚在VS2017中测试。

Jon Hanna 回复 5天 前

@Fay我猜它一定不是PCL API表面的一部分,尽管目前唯一支持PCL的东西也支持4.5,所以我已经不得不使用自己的Task.CompletedTask => Task.Delay(0);为了支持这一点,所以我不太清楚。

0
Alexander Trauzzi 回答 5天 前

最近遇到此问题,并不断收到有关方法无效的警告/错误。
我们的任务是安抚编译器,这就把它清理干净了:

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

这汇集了迄今为止所有建议中最好的建议。除非您在方法中实际执行某些操作,否则不需要返回语句。

Keith 回复 5天 前

这是完全错误的。您收到一个编译器错误,因为方法定义包含async,因此编译器需要等待。“正确”的用法是public Task myvoidAsyncMethodog(){return Task.CompletedTask;}

webwake 回复 5天 前

我不知道为什么会被否决,因为这似乎是最干净的答案

noelicus 回复 5天 前

因为基思的评论。

Alexander Trauzzi 回复 5天 前

他并不是完全错了,他只是删除了async关键字。我的方法更惯用。他是极简主义者。如果不是有点粗鲁的话。

Nick N. 回复 5天 前

这毫无意义,完全同意基思的观点,实际上我并没有得到所有的赞成票。为什么要添加不必要的代码?public Task MyVoidAsyncMethod() {}与上述方法完全相同。如果有这样使用它的用例,请添加其他代码。

Peter Bruins 回复 5天 前

我的用例是“public async Task myvoidasynchmethod(){#if!DEBUG..DoStuff…#endif await Task.CompletedTask;}”

Alexander Trauzzi 回复 5天 前

以避免出现无效警告。除非他们更新了编译器以停止这样做。

0
Xin 回答 5天 前
return Task.CompletedTask; // this will make the compiler happy
0
trashmaker_ 回答 5天 前

必须返回指定类型时:

Task.FromResult<MyClass>(null);