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 *************************
  • 相关阅读:
    MIne FirstBlog
    P6563 [SBCOI2020]一直在你身旁
    P6563 [SBCOI2020]一直在你身旁
    T122085 [SBCOI2020]时光的流逝
    LC 918. Maximum Sum Circular Subarray
    1026 Table Tennis
    LC 1442. Count Triplets That Can Form Two Arrays of Equal XOR
    LC 1316. Distinct Echo Substrings
    LC 493. Reverse Pairs
    1029 Median (二分)
  • 原文地址:https://www.cnblogs.com/anjingdian/p/15304192.html
Copyright © 2011-2022 走看看