.NET 中小心嵌套等待的 Task,它可能会耗尽你线程池的现有资源,出现类似死锁的情况

栏目: ASP.NET · 发布时间: 6年前

内容简介:一个简单的本文将以一个最简单的例子说明如何出现以及避免这样的问题。谁都不会认为

一个简单的 Task 不会消耗多少时间,但如果你不合适地将 Task 转为同步等待,那么也可能很快耗尽线程池的所有资源,出现类似死锁的情况。

本文将以一个最简单的例子说明如何出现以及避免这样的问题。

耗时的 Task.Run

谁都不会认为 Task.Run(() => 1) 这个异步任务执行会消耗多少时间。

但实际上,如果你的代码写得不清真,它真的能消耗大量的时间,这种时间消耗有点像死锁。

下图分别是 7 个这样的任务、8 个这样的任务和 16 个这样的任务的耗时:

.NET 中小心嵌套等待的 Task,它可能会耗尽你线程池的现有资源,出现类似死锁的情况

可以发现,8 个任务和 16 个任务的耗时很不正常。

在实际的测试当中,1~7 个任务的耗时几乎相同,而到后面没增加一个任务会增加大量时间。

最简复现代码

class Program
{
    static async Task Main(string[] args)
    {
        Console.Title = "walterlv task demo";

        var stopwatch = Stopwatch.StartNew();

        var task = Enumerable.Range(0, 8).Select(i => Task.Run(() => DoAsync(i).Result)).ToList();
        await Task.WhenAll(task);

        Console.WriteLine($"耗时: {stopwatch.Elapsed}");
        Console.Read();
    }

    private static async Task<int> DoAsync(int index)
    {
        return await Task.Run(() => 1);
    }
}

原因

你可以阅读 .NET 默认的 TaskScheduler 和线程池(ThreadPool)设置 了解线程池创建新工作线程的规则。这里其实真的是类似于死锁的一个例子。

  1. 一开始,我们创建了 n 个 Task,然后分别安排在线程池中执行,并在每个 Task 中等待任务执行完毕;
  2. 随后这 n 个 Task 分别再创建了 n 个子 Task,并继续安排在线程池中执行;
  3. 这时问题来了,由于前面 n 个 Task 在等待中,所以占用了线程池的线程资源:
    • 如果 n < 线程池最小线程数,那么当前线程池中还有剩余工作线程帮助完成子 Task;
    • 但如果 n >= 线程池最小线程数,那么当前线程池中便没有新的工作线程来完成子 Task;于是一开始的等待也不会完成;必须等线程池开启新的工作线程后,任务才可以继续。

带线程池开启新的线程之前,以上那些线程就是处于死锁的状态!由于线程池开启新的工作线程需要等待一段时间(例如每秒最多开启一个新的线程),所以每增加一个这样的任务,那么消耗的时间便会持续增加。

解决

去掉这里本来多余的 Task.Run 问题便可以解决。或者一直 async / await 中间不要转换为同步代码,那么问题也能解决。

我会遇到以上代码,是因为在库中写了类似 DoAsync 那样的方法。同时为了方便使用,封装了一个同步等待的属性。在业务使用方,觉得获取此属性可能比较耗时,于是用了 Task.Run 在后台线程调用。同时由于这是一个可能大量并发的操作,于是造成了以上悲剧。3


以上所述就是小编给大家介绍的《.NET 中小心嵌套等待的 Task,它可能会耗尽你线程池的现有资源,出现类似死锁的情况》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

概率编程实战

概率编程实战

[美]艾维·费弗 (Avi Pfeffer) / 姚军 / 人民邮电出版社 / 2017-4 / 89

概率推理是不确定性条件下做出决策的重要方法,在许多领域都已经得到了广泛的应用。概率编程充分结合了概率推理模型和现代计算机编程语言,使这一方法的实施更加简便,现已在许多领域(包括炙手可热的机器学习)中崭露头角,各种概率编程系统也如雨后春笋般出现。本书的作者Avi Pfeffer正是主流概率编程系统Figaro的首席开发者,他以详尽的实例、清晰易懂的解说引领读者进入这一过去令人望而生畏的领域。通读本书......一起来看看 《概率编程实战》 这本书的介绍吧!

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具