• C# Task 使用 WhenAll 和 WaitAll 需要注意的坑


    1.无限等待

    我们在使用 WhenAll 和 WaitAll 时,一定得要注意:1.必须添加超时时间,防止无限等待 2.等待的 Task 一定要保证是启动的。

    比如下面这种写法:

    using System;
    using System.Collections.Generic;
    using System.Threading.Tasks;
    
    namespace TaskForWhenAll
    {
        class Program
        {
            static void Main(string[] args)
            {
                var taskList = new List<Task>();
                for (int i = 0; i < 5; i++)
                {
                    taskList.Add(new Task(() =>
                    {
                        Console.WriteLine("Task {0} is finished", Task.CurrentId);
                    }));
                }
    
                // await Task.WhenAny(taskList);
                Task.WaitAll(taskList.ToArray());
                Console.WriteLine("exit");
            }
        }
    }
    

    将不会正常运行,会一直无限等待,因为 new Task 这样创建出来的 Task 不会自动运行,需要手动调用 Task.Start

    改造一下代码:

    using System;
    using System.Collections.Generic;
    using System.Threading.Tasks;
    
    namespace TaskForWhenAll
    {
        class Program
        {
            static void Main(string[] args)
            {
                var taskList = new List<Task>();
                for (int i = 0; i < 5; i++)
                {
                    taskList.Add(Task.Run(() =>
                    {
                        Console.WriteLine("Task {0} is finished", Task.CurrentId);
                    }));
                }
    
                // await Task.WhenAny(taskList);
                Task.WaitAll(taskList.ToArray());
                Console.WriteLine("exit");
            }
        }
    }
    

    使用 Task.Run 创建的 Task 是会自动运行的

    2.没有期望的等待

    我们在创建 Task 时,可能会定义一个异步委托,以便方便在 Task 里面使用 await,例如:

    class Program
    {
        static async Task Main(string[] args)
        {
            var taskList = new List<Task>();
            for (int i = 0; i < 5; i++)
            {
                taskList.Add(Task.Factory.StartNew(async () =>
                {
                    await Task.Delay(3000);
                    Console.WriteLine("Task {0} is finished", Task.CurrentId);
                }));
            }
    
            await Task.WhenAny(taskList);
            Console.WriteLine("exit");
        }
    }
    

    直接运行会发生什么

    直接就退出了,并没有等待所有任务执行完毕。

    我们换成 Task.Run 是可以正常运行的,这是为什么呢?这是因为我们这种写法,会把 Task Result 包装一层,我们需要得到期望的结果需要解除包装 UnWrap,Task.Factory.StartNew和Task.Run区别之一就有Task.Run会自动执行Unwrap操作。

    扩展阅读:https://www.cnblogs.com/Leo_wl/archive/2012/09/21/2696342.html

    我们改造一下代码

    taskList.Add(Task.Factory.StartNew(async () =>
                    {
                        await Task.Delay(3000);
                        Console.WriteLine("Task {0} is finished", Task.CurrentId);
                    }).Unwrap());
    

    就能按照我们期望的去运行

  • 相关阅读:
    团队项目—第二次冲刺计划
    第一阶段冲刺总结
    团队绩效评估
    回复其他小组对我们的评价
    软件项目评价
    maven 之分模块构建web项目 及 聚合与继承特性
    Log4j 使用总结
    freemarker 总结
    freemarker入门 之 脱离容器实现hello word
    读取txt文件 统计“java”出现的次数(大小写不敏感)
  • 原文地址:https://www.cnblogs.com/stulzq/p/16067610.html
Copyright © 2020-2023  润新知