RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 658470
Accepted
iluxa1810
iluxa1810
Asked:2020-04-26 00:56:46 +0000 UTC2020-04-26 00:56:46 +0000 UTC 2020-04-26 00:56:46 +0000 UTC

什么时候应该使用 ValueTask<T>?

  • 772

新版本的语言有一个创新ValueTask<T>。

我是否正确理解应该在任务完成速度可能比我所说的更快时使用它await?

通常的任务是死了还是在某些情况下仍然需要使用它?

c#
  • 3 3 个回答
  • 10 Views

3 个回答

  • Voted
  1. Best Answer
    Grundy
    2020-04-26T02:12:37Z2020-04-26T02:12:37Z

    Generalized async return types部分中的描述

    在某些情况下,从异步方法返回Task可能是性能瓶颈。Task是引用类型,所以在使用它的时候,对象的内存会分配在堆上。在带有修饰符的方法async返回缓存结果或同步执行的情况下,额外的堆分配可能会在代码的关键部分占用大量时间。如果这些分配发生在循环中,这可能会变得非常昂贵。

    新的语言特性允许异步方法返回Task,Task<T>和以外的类型void。返回类型仍必须满足异步模式,这意味着GetAwaiter. 作为一个具体示例,一个类型已添加到.NET 框架ValueTask中以利用新功能:

    public async ValueTask<int> Func()
    {
        await Task.Delay(100);
        return 5;
    }
    

    一个简单的优化是使用ValueTaskwhere formerly used Task。但是,如果您想添加额外的手动优化,您可以缓存异步工作的结果并在后续调用中使用这些结果。该结构ValueTask有一个Task作为参数的构造函数,因此您可以ValueTask从任何现有异步方法的返回值创建:

    public ValueTask<int> CachedFunc()
    {
        return (cache) ? new ValueTask<int>(cacheResult) : new ValueTask<int>(LoadCache());
    }
    private bool cache = false;
    private int cacheResult;
    private async Task<int> LoadCache()
    {
        // simulate async work:
        await Task.Delay(100);
        cacheResult = 100;
        cache = true;
        return cacheResult;
    }
    

    与所有性能建议一样,您应该在对代码进行重大更改之前比较这两种方法的结果。

    • 10
  2. Nikita
    2020-04-26T10:11:37Z2020-04-26T10:11:37Z

    @Grundy 的回答和@Qutrix的评论的一个小补充:

    为了让编译器允许您使用自己的类任务类型作为异步方法的返回值,您必须执行以下操作:

    1. 创建此类型。它可以是类或结构:

      public class MyTask { }
      
    2. 用属性标记它[AsyncMethodBuilder(typeof(MyTaskBuilder))]
    3. 实施类/结构MyTaskBuilder。将来,编译器将使用它来构造您的类任务类型(最小方法和属性集如下所示,并且必须存在于定义中MyTaskBuilder)

    public class MyTaskBuilder
    {
        public static MyTaskBuilder Create() => new MyTaskBuilder();
    
        public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine { }
    
        public void SetStateMachine(IAsyncStateMachine stateMachine) { }
    
        public void SetResult() { }
    
        public void SetException(Exception exception) { }
    
        public MyTask Task { get; }
    
        public void AwaitOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine)
            where TAwaiter : INotifyCompletion where TStateMachine : IAsyncStateMachine { }
    
        public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter,
            ref TStateMachine stateMachine) where TAwaiter : ICriticalNotifyCompletion
            where TStateMachine : IAsyncStateMachine { }
    }
    
    1. 最后,为了支持运算符await,还需要在类中实现一个MyTask公共方法,该方法GetAwaiter()的返回类型 ( MyTaskAwaiter) 必须实现接口INotifyCompletion,具有公共属性IsCompleted,当然还有方法GetResult()(将返回结果异步操作或无效)。

    [AsyncMethodBuilder(typeof(MyTaskBuilder))]
    public class MyTask
    {
        public static MyTask Run(Action action) { }
    
        public MyTaskAwaiter GetAwaiter() { }
    }
    
    public class MyTaskAwaiter : INotifyCompletion
    {
        public bool IsCompleted { get; }
    
        public void GetResult() { }
    
        public void OnCompleted(Action continuation) { }
    }
    

    因此我们能够写出类似的东西

    private async MyTask ExecuteAsync()
    {
        await MyTask.Run(() => { });
    }
    
    • 9
  3. Pavel Mayorov
    2020-05-03T13:54:07Z2020-05-03T13:54:07Z

    我是否正确理解当任务完成速度可能比我调用 await 快时应该使用它?

    一般情况下是正确的,但有一点修正:当任务有可能在不中断执行的情况下完成时。或者,等价地,如果它可以同步执行。这与不调用 await 不同,因为如果在已完成的任务上调用 await 运算符,它不会中断方法的执行。

    例如,下面的方法将被同步执行:

    async ValueTask<bool> Foo() {
        await Task.Completed;
        await Task.FromResult(1);
        return await Task.FromResult(false);
    }
    
    • 4

相关问题

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    Python 3.6 - 安装 MySQL (Windows)

    • 1 个回答
  • Marko Smith

    C++ 编写程序“计算单个岛屿”。填充一个二维数组 12x12 0 和 1

    • 2 个回答
  • Marko Smith

    返回指针的函数

    • 1 个回答
  • Marko Smith

    我使用 django 管理面板添加图像,但它没有显示

    • 1 个回答
  • Marko Smith

    这些条目是什么意思,它们的完整等效项是什么样的

    • 2 个回答
  • Marko Smith

    浏览器仍然缓存文件数据

    • 1 个回答
  • Marko Smith

    在 Excel VBA 中激活工作表的问题

    • 3 个回答
  • Marko Smith

    为什么内置类型中包含复数而小数不包含?

    • 2 个回答
  • Marko Smith

    获得唯一途径

    • 3 个回答
  • Marko Smith

    告诉我一个像幻灯片一样创建滚动的库

    • 1 个回答
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Алексей Шиманский 如何以及通过什么方式来查找 Javascript 代码中的错误? 2020-08-03 00:21:37 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    user207618 Codegolf——组合选择算法的实现 2020-10-23 18:46:29 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5