zoukankan      html  css  js  c++  java
  • c#多线程之Task

    需求:比如说开始一个项目,首先拆分模块交给不同的人干,全部干完之后进行整合测试,项目完结。其中拆分模块之后每个人都做不同的工作,这是完全可以并行操作的,所以可以使用多线程,比如:

    代码:

            /// <summary>
            /// Task专题解析
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void btnTask_Click(object sender, EventArgs e)
            {
                Console.WriteLine($"****** **btnTask_Click   异步方法 start {Thread.CurrentThread.ManagedThreadId}-{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}*************************");
                Console.WriteLine("项目开始");
                Console.WriteLine("拆分模块");
                Console.WriteLine("指定开发人员开发对应模块");
                Task.Run(() => this.Coding("张三", "Website"));
                Task.Run(() => this.Coding("李四", "WebApi")); 
                Console.WriteLine("整合测试");
                Console.WriteLine("项目结束");
                Console.WriteLine($"**** *****btnTask_Click   异步方法 end {Thread.CurrentThread.ManagedThreadId} -{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} *************************");
    
            }
            /// <summary>
            /// 编码模拟
            /// </summary>
            /// <param name="name"></param>
            /// <param name="project"></param>
            private void Coding(string name, string project)
            {
                Console.WriteLine($"***** *********Coding  start {name}- {project}-{Thread.CurrentThread.ManagedThreadId.ToString()}-{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}** ***********");
                long IResult = 0;
                for (int i = 0; i < 1000000000; i++)
                {
                    IResult = i;
                }
                Console.WriteLine($"***** ***********Coding end {name}- {project}-{Thread.CurrentThread.ManagedThreadId.ToString()}-{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}** **********");
    
            }

    结果:

    ****** **btnTask_Click   异步方法 start 1-2021-09-17 18:21:07*************************
    项目开始
    拆分模块
    指定开发人员开发对应模块
    整合测试
    项目结束
    **** *****btnTask_Click   异步方法 end 1 -2021-09-17 18:21:07 *************************
    **************************Coding  start 张三- Website-4-2021-09-17 18:21:07*************************
    **************************Coding  start 李四- WebApi-7-2021-09-17 18:21:07*************************
    **************************Coding end 李四- WebApi-7-2021-09-17 18:21:09*************************
    **************************Coding end 张三- Website-4-2021-09-17 18:21:09*************************

     从这个结果可以看出,不符合实际情况,因为之后模块全部开发完成之后才能项目结束。所以改成下面代码:

     /// <summary>
            /// Task专题解析
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void btnTask_Click(object sender, EventArgs e)
            {
                Console.WriteLine($"****** **btnTask_Click   异步方法 start {Thread.CurrentThread.ManagedThreadId}-{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}*************************");
                Console.WriteLine("项目开始");
                Console.WriteLine("拆分模块");
                Console.WriteLine("指定开发人员开发对应模块");
                List<Task> taskList = new List<Task>();
                taskList.Add(Task.Run(() => this.Coding("张三", "Website")));
                taskList.Add(Task.Run(() => this.Coding("李四", "WebApi")));
    
                // 等待提供的所有 System.Threading.Tasks.Task 对象完成执行过程。
                Task.WaitAll(taskList.ToArray()); 
                Console.WriteLine("整合测试");
                Console.WriteLine("项目结束");
                Console.WriteLine($"**** *****btnTask_Click   异步方法 end {Thread.CurrentThread.ManagedThreadId} -{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} *************************");
    
            }

    结果:

    ****** **btnTask_Click   异步方法 start 1-2021-09-17 18:26:19*************************
    项目开始
    拆分模块
    指定开发人员开发对应模块
    *** **Coding  start 张三- Website-3-2021-09-17 18:26:19***** ***
    *** **Coding  start 李四- WebApi-4-2021-09-17 18:26:19***** ***
    *** ****Coding end 李四- WebApi-4-2021-09-17 18:26:22********** *
    *** ****Coding end 张三- Website-3-2021-09-17 18:26:22********** *
    整合测试
    项目结束
    **** *****btnTask_Click   异步方法 end 1 -2021-09-17 18:26:22 *************************

    还有一种方法WaitAny,只要传入参数中的任何一个线程结束了,就可以再继续往下执行。

         private void btnTask_Click(object sender, EventArgs e)
            {
                Console.WriteLine($"****** **btnTask_Click   异步方法 start {Thread.CurrentThread.ManagedThreadId}-{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}*************************");
                Console.WriteLine("项目开始");
                Console.WriteLine("拆分模块");
                Console.WriteLine("指定开发人员开发对应模块");
                List<Task> taskList = new List<Task>();
                taskList.Add(Task.Run(() => this.Coding("张三", "Website")));
                taskList.Add(Task.Run(() => this.Coding("李四", "WebApi")));
                //只有taskList中有一个线程执行完毕就不会再阻塞当前主线程,使其继续往下执行
                Task.WaitAny(taskList.ToArray());
                Console.WriteLine("项目开发里程碑达成");
                // 等待提供的所有 System.Threading.Tasks.Task 对象完成执行过程。
                Task.WaitAll(taskList.ToArray());
                Console.WriteLine("整合测试");
                Console.WriteLine("项目结束");
                Console.WriteLine($"**** *****btnTask_Click   异步方法 end {Thread.CurrentThread.ManagedThreadId} -{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} *************************");
    
            }

    结果:李四率先完成,所以可以接着向下执行。

    ****** **btnTask_Click   异步方法 start 1-2021-09-17 18:35:30*************************
    项目开始
    拆分模块
    指定开发人员开发对应模块
    *** **Coding  start 张三- Website-3-2021-09-17 18:35:30***** ***
    *** **Coding  start 李四- WebApi-4-2021-09-17 18:35:30***** ***
    *** ****Coding end 李四- WebApi-4-2021-09-17 18:35:32********** *
    项目开发里程碑达成
    *** ****Coding end 张三- Website-3-2021-09-17 18:35:32********** *
    整合测试
    项目结束
    **** *****btnTask_Click   异步方法 end 1 -2021-09-17 18:35:32 *************************

    但是上面这2种方法都是阻塞的主线程,所以当前的界面是不能再响应其他操作(只有主线程才能响应界面操作),比如无法拖动,点击等。

    可以使用TaskFactory类来解决:

            /// <summary>
            /// Task专题解析
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void btnTask_Click(object sender, EventArgs e)
            {
                Console.WriteLine($"****** **btnTask_Click   异步方法 start {Thread.CurrentThread.ManagedThreadId}-{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}*************************");
                Console.WriteLine("项目开始");
                Console.WriteLine("拆分模块");
                Console.WriteLine("指定开发人员开发对应模块");
                List<Task> taskList = new List<Task>();
                taskList.Add(Task.Run(() => this.Coding("张三", "Website")));
                taskList.Add(Task.Run(() => this.Coding("李四", "WebApi")));
                TaskFactory taskFactory = new TaskFactory();
                //任一线程执行完毕之后取消主线程的阻塞
                taskFactory.ContinueWhenAny(taskList.ToArray(), t =>
                {
                    Console.WriteLine($"{t.AsyncState}第一个完成");
                });
                //全部线程执行完毕之后取消主线程的阻塞
                taskFactory.ContinueWhenAll(taskList.ToArray(), tArr =>
                {
                    Console.WriteLine($"整合测试"); 
                });


                    Task.WaitAll(taskList.ToArray());  

                    Console.WriteLine($"项目完成");

                Console.WriteLine($"**** *****btnTask_Click   异步方法 end {Thread.CurrentThread.ManagedThreadId} -{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} *************************");
    
            }

    结果:

    ****** **btnTask_Click   异步方法 start 1-2021-09-17 19:04:28*************************
    项目开始
    拆分模块
    指定开发人员开发对应模块
    项目完成
    **** *****btnTask_Click   异步方法 end 1 -2021-09-17 19:04:28 *************************
    *** **Coding  start 李四- WebApi-7-2021-09-17 19:04:29***** ***
    *** **Coding  start 张三- Website-6-2021-09-17 19:04:29***** ***
    *** ****Coding end 李四- WebApi-7-2021-09-17 19:04:31********** *
    第一个完成
    *** ****Coding end 张三- Website-6-2021-09-17 19:04:31********** *
    整合测试

    但是由于多线程是无序性的,看上面的结果,项目完成这句话的输出跑前面去了,比项目测试还早,按照业务逻辑来说只能先测试没问题了才能宣告项目的结束。 

         private void btnTask_Click(object sender, EventArgs e)
            {
                Console.WriteLine($"****** **btnTask_Click   异步方法 start {Thread.CurrentThread.ManagedThreadId}-{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}*************************");
                Console.WriteLine("项目开始");
                Console.WriteLine("拆分模块");
                Console.WriteLine("指定开发人员开发对应模块");
                List<Task> taskList = new List<Task>();
                taskList.Add(Task.Run(() => this.Coding("张三", "Website")));
                taskList.Add(Task.Run(() => this.Coding("李四", "WebApi")));
                TaskFactory taskFactory = new TaskFactory();
                //任一线程执行完毕之后取消主线程的阻塞
                taskFactory.ContinueWhenAny(taskList.ToArray(), t =>
                {
                    Console.WriteLine($"{t.AsyncState}第一个完成");
                });
                //改成下面这种形式,因为ContinueWhenAll方法的返回值是一个Task,这样的话在下面Task.WaitAll(taskList.ToArray());中就可以阻塞所有的子线程了,就能够按照顺序执行
                taskList.Add(taskFactory.ContinueWhenAll(taskList.ToArray(), tArr =>
               {
                   Console.WriteLine($"整合测试");
               }));
    
                Task.WaitAll(taskList.ToArray());
                Console.WriteLine($"项目完成");
                Console.WriteLine($"**** *****btnTask_Click   异步方法 end {Thread.CurrentThread.ManagedThreadId} -{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} *************************");
    
            }

    结果:

    ****** **btnTask_Click   异步方法 start 1-2021-09-17 19:43:26*************************
    项目开始
    拆分模块
    指定开发人员开发对应模块
    *** **Coding  start 张三- Website-3-2021-09-17 19:43:26***** ***
    *** **Coding  start 李四- WebApi-4-2021-09-17 19:43:26***** ***
    *** ****Coding end 张三- Website-3-2021-09-17 19:43:28********** *
    第一个完成
    *** ****Coding end 李四- WebApi-4-2021-09-17 19:43:28********** *
    整合测试
    项目完成
    **** *****btnTask_Click   异步方法 end 1 -2021-09-17 19:43:28 *************************
  • 相关阅读:
    python os的一些用法(-)
    python常用函数 time.strftime
    centos7 解压rar 文件
    centos7 开机启动设置
    python基础之Day15
    python基础之Day13
    python基础之Day12
    python基础之Day11
    python基础之Day10
    python基础之Day9
  • 原文地址:https://www.cnblogs.com/anjingdian/p/15304192.html
Copyright © 2011-2022 走看看