RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 1194331
Accepted
Andrei Khotko
Andrei Khotko
Asked:2021-10-23 18:14:44 +0000 UTC2021-10-23 18:14:44 +0000 UTC 2021-10-23 18:14:44 +0000 UTC

任务在什么情况下被销毁?

  • 772

一个抽象的例子:有一个_reader,它异步读取数据。有一个 ,当应用程序退出时cancellationToken将变为:Cancel

while (!cancellationToken.IsCancellationRequested)
{
    var readingTask = _reader.ReadAsync();
    await Task.WhenAny(readingTask, Task.Delay(Timeout.Infinite, cancellationToken));
    
    if (readingTask.IsCompletedSuccessfully)
    {
        var readResult = readingTask.Result;
        // Обрабатываем readResult
    }
}

假设循环已经执行了 40 次,会不会因为循环的每次迭代都会创建一个Task.Delay(Timeout.Infinite, cancellationToken)只有在 token 为 时才会完成的任务而导致内存被污染或性能下降Cancel?或者垃圾收集器(或其他人)会破坏这些无休止的任务吗?

c#
  • 2 2 个回答
  • 10 Views

2 个回答

  • Voted
  1. Best Answer
    Pavel Mayorov
    2021-10-23T18:54:14Z2021-10-23T18:54:14Z

    像任何对象一样,当没有对它的引用时,Task 将被销毁。通常有两个参考:

    1. 来自对象的消费者(正在等待的人);
    2. 从谁做的工作。

    您自己持有第一个引用(对于临时对象,只有 await 运算符“持有”它)。但是第二个链接一直存在,直到任务完成或取消。

    因此,为了销毁一个任务,消费者通常有必要且足够的忘记它并取消工作。但每个个案可能都有自己的特点。


    现在关于Task.Delay. 对的引用Task.Delay由活动定时器持有,并在定时器被取消时丢失。因此,您所要做的就是取消 GC 收集对象的计时器:

    using (var tempCts = CancellationTokenSource.CreateLinkedSource(cancellationToken)) {
        await Task.WhenAny(readingTask, Task.Delay(Timeout.Infinite, tempCts.Token));
        tempCts.Cancel(); // отменяет таймер и даёт собрать задачу
    }
    

    但是,从 判断Timeout.Infinite,我看到这个任务是“永恒的”。在这里你可以不用Task.Delay:

    var tcs = new TaskCompletionSource<object>();
    using (cancellationToken.Register(tcs.SetCanceled))
         await Task.WhenAny(readingTask, tcs.Task);
    

    我注意到这里需要 using ,否则对 tcs 的引用将由取消令牌持有。


    PS第三种方式来做你所追求的是这个:

    await readingTask.ContinueWith(_ => {}, cancellationToken);
    

    这里ContinueWith也创建了一个临时任务,该任务的链接一直保持到它完成或取消(但是,与选项不同的是Task.Delay,它在完成后立即结束readingTask)。

    • 4
  2. CrazyElf
    2021-10-23T18:30:40Z2021-10-23T18:30:40Z

    我测试了退化的情况 - 根本没有cancellationToken,在我看来这在这里并不重要。结果 - 尽管垃圾收集器工作,内存仍然结束。

    using System;
    using System.Threading.Tasks;
                        
    public class Program
    {
        public static async void Main()
        {
            Console.WriteLine("Begin...");
            Console.WriteLine("Memory used {0:N0}", GC.GetTotalMemory(false));
            for(var i = 0; i < 100000; i++)
            {
                await Task.WhenAny(Task.CompletedTask, Task.Delay(100000));
                if(i % 10000 == 0)
                {
                    Console.WriteLine("Collecting");
                    GC.Collect();
                    GC.Collect();
                    Console.WriteLine("Memory used {0:N0}", GC.GetTotalMemory(true));
                }
            }
            Console.WriteLine("Hello World!");
        }
    }
    

    结论:

    Begin...
    Memory used 8,159,128
    Collecting
    Memory used 7,964,504
    Collecting
    Memory used 27,284,692
    Fatal Error: Memory usage limit was exceeded
    

    链接您可以在其中检查代码是否有效。

    • 2

相关问题

  • 使用嵌套类导出 xml 文件

  • 分层数据模板 [WPF]

  • 如何在 WPF 中为 ListView 手动创建列?

  • 在 2D 空间中,Collider 2D 挂在玩家身上,它对敌人的重量相同,我需要它这样当它们碰撞时,它们不会飞向不同的方向。统一

  • 如何在 c# 中使用 python 神经网络来创建语音合成?

  • 如何知道类中的方法是否属于接口?

Sidebar

Stats

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

    如何从列表中打印最大元素(str 类型)的长度?

    • 2 个回答
  • Marko Smith

    如何在 PyQT5 中清除 QFrame 的内容

    • 1 个回答
  • Marko Smith

    如何将具有特定字符的字符串拆分为两个不同的列表?

    • 2 个回答
  • Marko Smith

    导航栏活动元素

    • 1 个回答
  • Marko Smith

    是否可以将文本放入数组中?[关闭]

    • 1 个回答
  • Marko Smith

    如何一次用多个分隔符拆分字符串?

    • 1 个回答
  • Marko Smith

    如何通过 ClassPath 创建 InputStream?

    • 2 个回答
  • Marko Smith

    在一个查询中连接多个表

    • 1 个回答
  • Marko Smith

    对列表列表中的所有值求和

    • 3 个回答
  • Marko Smith

    如何对齐 string.Format 中的列?

    • 1 个回答
  • Martin Hope
    Alexandr_TT 2020年新年大赛! 2020-12-20 18:20:21 +0000 UTC
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +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
    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