C#中的各种多线程使用场景的demo,便于快速对号入座使用

C#中的各种多线程使用场景的demo,便于快速对号入座使用

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace MyThreadDemo
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }




        //同步异步:
        #region MyRegion
        //1. 进程/线程/多线程
        //2. 同步异步
        //3. 异步的三大特点
        //4. C#中的多线程

        //一、进程:计算机概念,虚拟的记录,描述一个应用程序在计算机上运行的时候,所消耗的各种资源的集合---Cpu+内容+磁盘IO+网络资源;
        //---类似于某一个公司---公司正常运作;

        //二、线程:(计算机资源)一个程序的进程中,所执行的具体的某一个动作的最小执行流;小到点击某个按钮,大到通过网络发送一句话出去;
        //具体到某一个人:
        //进程必然是包含了多个线程;线程是依附于进程存在的;如果进程不在了,线程也随之消失了;


        //三、句柄:是一个long了类型的数字,对应这计算机程序中的某一个小部件;要操作程序,对应的最小的单位;
        //公司中的任何一个物件--编号--计算机---会给计算机坐个编号---(部门---座位号)

        //四、为什么计算机可以多线程?跟计算机的CPU的核数有关;
        //6核12线程:把六个核心进行逻辑切分:如果有动作需要计算机响应,操作系统就会去申请CPU来处理;CPU在执行动作的时候,CPU是分片执行:
        //分片:把每一个核每一毫秒可以执行的动作,切分成10000份;操作系统在调度的时候,执行动作,切分后去执行的多个动作的时候;开始动作A,使用的是分片后的某一份;  结束的时候,可能使用的是另外的某一份; 
        //计算机在不断的调度过程中;
        //1.从宏观角度来说:多个动作,就可以做到在某一段时间内;看似同时执行完毕了;
        //2.从微观的角度来说:某一时刻,同意时刻只能处理一件事儿--串行执行;

        //五、C#中的多线程:Thread/ThreadPool/Task 都是C#语言在操作计算机的资源(线程)时;封装的一个帮助类库;
        //线程:---同步异步:
        //单线程执行代码命令:同步执行;
        //同步方法:
        //1.线性执行,从上往下依次执行--很符合我们人类的思维逻辑,线程ID为01  (主线程/UI线程)
        // 请人吃饭:真心的请人吃饭;Richard老师请Vn吃饭;说:Vn,晚上一起去吃饭;Vn:我还要忙一会儿,Richard:那好,我等你;等你忙完,我们一起去吃饭;
        //2.同步方法执行慢;卡顿界面--只有一个线程参与计算---CPU太忙,根本无暇他顾;只有一个线程执行动作; 消耗的计算机资源少(工钱少)
        //3.同步方法:有序执行;
        

        //多线程执行代码命令:异步执行:
        //异步方法:
        //1.开启了一个新的线程(多线程--子线程)(有一个新的线程Id);且不再是线型执行了;  UI线程不等待子线程执行完毕;主线程直接往后执行;  子线程延迟执行 
        //请人吃饭:客气一下请人吃饭:Richard老师客气一下请人Vn吃饭,说:Vn,晚上一起吃饭,Vn:我还要忙一会儿,Richard:那你先忙吧,我就先去吃饭了,你忙完自己去吃饭吧!
        //2.异步方法执行快:不卡顿界面;开启了一个新的线程去执行去了;开启了五个线程去执行动作:消耗的计算机资源多(工钱多)
        //  异步方法--多线程方法--以资源换时间; 使用大量的资源,降低时间成本;
        //3.无序执行:线程开启无法控制谁先谁后;线程执行计算结束也无法控制谁先谁后;---多线程异步执行:无序执行;


        #endregion
        //Thread
        //ThreadPool
        //Task
        /// <summary>
        /// 同步方法
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnSync_Click(object sender, EventArgs e)
        {
            Debug.WriteLine($"****************btnSync_Click Start {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");

            for (int i = 0; i < 5; i++)
            {
                DoSomething("kulala");
            }

            Debug.WriteLine($"****************btnSync_Click End   {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
        }

        /// <summary>
        /// 异步方法
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnAsnyc_Click(object sender, EventArgs e)
        {
            Debug.WriteLine($"****************btnAsyncAdvanced_Click Start {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");

            #region 委托异步调用
            //在ASP.NET Core的年代:BeginInvoke不再支持了;如果想要看看这个,可以参考第14期;
            //Action<string> action = this.DoSomething;
            //AsyncCallback asyncCallback = null;
            //action.BeginInvoke(" Richard ", asyncCallback, "Object");
            #endregion

            //Task开启了一个线程 
            for (int i = 0; i < 5; i++)
            {
                Task.Run(() =>
                {
                    DoSomething("kulala");
                }); 
            }
             
            Debug.WriteLine($"****************btnAsyncAdvanced_Click End   {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
        }

        #region Private Method

        /// <summary>
        /// 一个比较耗时耗资源的私有方法
        /// </summary>
        /// <param name="name"></param>
        private void DoSomething(string name)
        {
            Debug.WriteLine($"****************DoSomething Start  {name}  {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
            long lResult = 0;
            for (int i = 0; i < 1000_000_000; i++)
            {
                lResult += i;
            }
            Thread.Sleep(2000);
            Debug.WriteLine($"****************DoSomething   End  {name}  {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")} {lResult}***************");
        }


        #endregion
    }
}

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace MyThreadDemo
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }




        //同步异步:
        #region MyRegion
        //1. 进程/线程/多线程
        //2. 同步异步
        //3. 异步的三大特点
        //4. C#中的多线程

        //一、进程:计算机概念,虚拟的记录,描述一个应用程序在计算机上运行的时候,所消耗的各种资源的集合---Cpu+内容+磁盘IO+网络资源;
        //---类似于某一个公司---公司正常运作;

        //二、线程:(计算机资源)一个程序的进程中,所执行的具体的某一个动作的最小执行流;小到点击某个按钮,大到通过网络发送一句话出去;
        //具体到某一个人:
        //进程必然是包含了多个线程;线程是依附于进程存在的;如果进程不在了,线程也随之消失了;


        //三、句柄:是一个long了类型的数字,对应这计算机程序中的某一个小部件;要操作程序,对应的最小的单位;
        //公司中的任何一个物件--编号--计算机---会给计算机坐个编号---(部门---座位号)

        //四、为什么计算机可以多线程?跟计算机的CPU的核数有关;
        //6核12线程:把六个核心进行逻辑切分:如果有动作需要计算机响应,操作系统就会去申请CPU来处理;CPU在执行动作的时候,CPU是分片执行:
        //分片:把每一个核每一毫秒可以执行的动作,切分成10000份;操作系统在调度的时候,执行动作,切分后去执行的多个动作的时候;开始动作A,使用的是分片后的某一份;  结束的时候,可能使用的是另外的某一份; 
        //计算机在不断的调度过程中;
        //1.从宏观角度来说:多个动作,就可以做到在某一段时间内;看似同时执行完毕了;
        //2.从微观的角度来说:某一时刻,同意时刻只能处理一件事儿--串行执行;

        //五、C#中的多线程:Thread/ThreadPool/Task 都是C#语言在操作计算机的资源(线程)时;封装的一个帮助类库;
        //线程:---同步异步:
        //单线程执行代码命令:同步执行;
        //同步方法:
        //1.线性执行,从上往下依次执行--很符合我们人类的思维逻辑,线程ID为01  (主线程/UI线程)
        // 请人吃饭:真心的请人吃饭;Richard老师请Vn吃饭;说:Vn,晚上一起去吃饭;Vn:我还要忙一会儿,Richard:那好,我等你;等你忙完,我们一起去吃饭;
        //2.同步方法执行慢;卡顿界面--只有一个线程参与计算---CPU太忙,根本无暇他顾;只有一个线程执行动作; 消耗的计算机资源少(工钱少)
        //3.同步方法:有序执行;


        //多线程执行代码命令:异步执行:
        //异步方法:
        //1.开启了一个新的线程(多线程--子线程)(有一个新的线程Id);且不再是线型执行了;  UI线程不等待子线程执行完毕;主线程直接往后执行;  子线程延迟执行 
        //请人吃饭:客气一下请人吃饭:Richard老师客气一下请人Vn吃饭,说:Vn,晚上一起吃饭,Vn:我还要忙一会儿,Richard:那你先忙吧,我就先去吃饭了,你忙完自己去吃饭吧!
        //2.异步方法执行快:不卡顿界面;开启了一个新的线程去执行去了;开启了五个线程去执行动作:消耗的计算机资源多(工钱多)
        //  异步方法--多线程方法--以资源换时间; 使用大量的资源,降低时间成本;
        //3.无序执行:线程开启无法控制谁先谁后;线程执行计算结束也无法控制谁先谁后;---多线程异步执行:无序执行;


        #endregion
        //Thread
        //ThreadPool
        //Task
        /// <summary>
        /// 同步方法
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnSync_Click(object sender, EventArgs e)
        {
            Debug.WriteLine($"****************btnSync_Click Start {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");

            for (int i = 0; i < 5; i++)
            {
                DoSomething("kulala");
            }

            Debug.WriteLine($"****************btnSync_Click End   {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
        }

        /// <summary>
        /// 异步方法
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnAsnyc_Click(object sender, EventArgs e)
        {
            Debug.WriteLine($"****************btnAsyncAdvanced_Click Start {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");

            #region 委托异步调用
            //在ASP.NET Core的年代:BeginInvoke不再支持了;如果想要看看这个,可以参考第14期;
            //Action<string> action = this.DoSomething;
            //AsyncCallback asyncCallback = null;
            //action.BeginInvoke(" Richard ", asyncCallback, "Object");
            #endregion

            //Task开启了一个线程 
            for (int i = 0; i < 5; i++)
            {
                Task.Run(() =>
                {
                    DoSomething("kulala");
                });
            }

            Debug.WriteLine($"****************btnAsyncAdvanced_Click End   {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
        }

        #region Private Method

        /// <summary>
        /// 一个比较耗时耗资源的私有方法
        /// </summary>
        /// <param name="name"></param>
        private void DoSomething(string name)
        {
            Debug.WriteLine($"****************DoSomething Start  {name}  {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
            long lResult = 0;
            for (int i = 0; i < 1000_000_000; i++)
            {
                lResult += i;
            }
            Thread.Sleep(2000);
            Debug.WriteLine($"****************DoSomething   End  {name}  {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")} {lResult}***************");
        }


        #endregion


        /// <summary>
        /// Task:
        /// 
        ///在最老版本中,有Thread/ThreadPool
        ///在前几天,在QQ大群有相关的公告的,你们下载观看
        ///1..NetFramework3.0时代实现
        ///2.C#中多线程操作的最佳实现---丰富的Api,我们在开发中遇到个各种场景,他都可以满足到;3.Task操作的线程来自于线程/池  
        ///Task,Prallel他们所操作的线程都是来自于线程池;
        /// 
        ///确定线程的标识:线程Id,线程Id不一样,线程其实就是不同的线程;
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>

        private void btnTask_Click(object sender, EventArgs e)
        {
            Debug.WriteLine($"****************btnTask_Click Start|| 线程ID: {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
            //一、Task开启线程有哪些方式:
            #region MyRegion
            //多线程:他的应用场景:
            //一、在什么情况下,可以使用多线程?
            //1.一个数据库查询:---可以使用多线程吗?不适合使用多线程;因为只有一个动作;不存在多个动作并发执行;
            //2.如果要同时去查询接口+查询缓存+查询数据库?--适合使用多线程吗?---可以开启三个线程;每个线程就负责一个动作; 
            //通过一个案例,来解析: 

            //二、高级班VIP课程讲课:
            //1.开始上课---Richard老师开始讲课--一节一节的开始讲:适合使用多线程吗?--不适合:不能同时讲多个课
            //。。。。。经过大概8个月的时间
            //2.开始项目实战---分组进行;多人合作完成; 适合使用多线程吗? ---适合;每个人就可以对应一个线程;多个人同时去开发功能---多线程并发;

            //3.如果大家其中有一个人完成了功能的开发,Richard老师就要开始准备环境了。
            //a.需要等待一堆线程中的某一个线程执行结束,马上触发一个动作;
            //解决方案: Task.WaitAny--等待几个线程中的某一个线程执行结束;---主线程会等待---会卡顿界面;一直到某一个线程执行结束后,才往后执行;--体验不好 
            //4.如果所有人开发完毕了,庆祝一下,一起吃个饭;

            //三、应用场景:
            //1.ContinueWhenAny
            //如果需要在一堆任务中,某一种执行结束后,去触发一个动作;


            //2.ContinueWhenAll
            //如果需要回调---如果需要控制顺序:

            //3.WaitAny
            //   有一个列表数据:有可能是来自于第三方接口,有可能是来自于缓存,也有可能是来自于数据库,查询的时候,我们不确定;
            // 常规玩法: 先找缓存,如果有数据,直接返回了,如果缓存没有--可能要去查询数据库,如果数据库有数据,直接返回,如果没有---查询第三方接口;
            // 多线程:同时开启三个线程,同时去查询三个地方的数据,只要是有一个地方的数据查询到了,只要是有一个地方的数据找到了,其他的两个线程我们就不管了;直接把找到的数据返回给前端就可以了;
            //
            //
            //4.WaitAll
            // 如果有一个首页,首页中包含了很多功能:考勤信息,年度top10,季度top10,公告,通知;
            // 在主页中:要加载主页-这些信息都需要查询出来: 而且这些信息都是来自于不同的地方,有的来自于接口,有的来自于缓存有的都来于数据库: 
            //有几个块信息,就开启几个线程,同时分别去各自的地方进行查询各自的数据;可以在后台等待所有的子线程执行结束;拿到结果、组件一个大的复杂实体对象,传递给视图,通过视图做绑定;--让查询并发执行: 但是这里如果是使用C#开发,不做前后端分离的话,可以考虑这种,可以提高性能;
            //现在更多的时候,可能是使用异步Ajax来完成---用户体验会更好;  资源会有所浪费,但是性能可以提高;

            #endregion

            //父子级线程
            //一个Task内部,开启了几个线程以后;Task内部的线程可以理解为子线程;
            //父线程在等待的时候,子线程没有线程等待;子线程可能内容还没有执行万一,父线程就已经结束了;
            {
                Task task = new Task(() =>
                {
                    Debug.WriteLine($"****************task开始了: {Thread.CurrentThread.ManagedThreadId.ToString("00")} ***************");
                    Task task1 = new Task(() =>
                    {
                        Debug.WriteLine($"****************task1: {Thread.CurrentThread.ManagedThreadId.ToString("00")} ***************");
                        Thread.Sleep(1000);
                        Debug.WriteLine("我是task1线程");
                    });

                    Task task2 = new Task(() =>
                    {
                        Debug.WriteLine($"****************task2: {Thread.CurrentThread.ManagedThreadId.ToString("00")} ***************");
                        Thread.Sleep(1000);
                        Debug.WriteLine("我是task2线程");
                    });
                    task1.Start();
                    task2.Start();

                    //task1.Wait();
                    //task2.Wait();

                    Debug.WriteLine($"****************task: {Thread.CurrentThread.ManagedThreadId.ToString("00")} ***************");
                });
                task.Start();//线程启动了
                task.Wait();   //单个线程的等待;等待task 内部的内容执行完毕,这里会卡顿界面;是主线程等待;

                // task.Wait();//等待执行完成:
                task.Wait(TimeSpan.FromMilliseconds(1100));
                task.Wait(1000);//限时等待;过时不候

                // Thread thread = null;

                //thread.Abort();//线程停止;
                //thread.Start();
                //thread.IsBackground = true;//后台线程:进程结束,线程随之消失
                //thread.IsBackground = false;//前台线程:进程结束,线程把内部需要执行的动作执行完毕,然后消失

            }

            //TaskCreationOptions.PreferFairness 相对来说比较公平执行的:如果是先申请的线程,就会优先执行;
            {
                //Task task1= new Task(() =>
                //{

                //}, TaskCreationOptions.PreferFairness);

                //Task task2 = new Task(() =>
                //{

                //}, TaskCreationOptions.PreferFairness);

            }
            {
                //    {
                //        Stopwatch stopwatch = new Stopwatch();
                //        stopwatch.Start();
                //        Thread.Sleep(3000);//主线程执行到这儿会卡顿等待;等待3000ms后继续往后;   
                //        stopwatch.Stop();
                //        Debug.WriteLine($"Thread.Sleep(3000):{stopwatch.ElapsedMilliseconds}");
                //    }
                //    {
                //        Stopwatch stopwatch = new Stopwatch();
                //        stopwatch.Start(); 
                //        //回调:Delay一般和ContinueWith配合使用;
                //        //不卡顿界面:3000ms以后,去执行一段业务逻辑:执行的动作就是ContinueWith内部的委托;ContinueWith内部的执行有可能是一个全新的线程去执行,也有可能是主线程去执行; 
                //        Task.Delay(3000).ContinueWith(t =>
                //        {
                //            Debug.WriteLine($"****************Delay || 线程ID:  {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
                //            stopwatch.Stop();
                //            Debug.WriteLine($"Task.Delay(3000):{stopwatch.ElapsedMilliseconds}");
                //        });//一般情况下,这个Delay 是等待3000ms继续做点什么---或者说延迟3000ms后做点什么; 
                //    }
            }

            //现在是20:56,大家休息5分钟&&上厕所,21:01继续~~
            //
            //多线程:他的应用场景:
            //一、在什么情况下,可以使用多线程?
            //1.一个数据库查询:---可以使用多线程吗?不适合使用多线程;因为只有一个动作;不存在多个动作并发执行;
            //2.如果要同时去查询接口+查询缓存+查询数据库?--适合使用多线程吗?---可以开启三个线程;每个线程就负责一个动作; 
            //通过一个案例,来解析: 

            //二、高级班VIP课程讲课:
            //1.开始上课---Richard老师开始讲课--一节一节的开始讲:适合使用多线程吗?--不适合:不能同时讲多个课
            //。。。。。经过大概8个月的时间
            //2.开始项目实战---分组进行;多人合作完成; 适合使用多线程吗? ---适合;每个人就可以对应一个线程;多个人同时去开发功能---多线程并发;

            //3.如果大家其中有一个人完成了功能的开发,Richard老师就要开始准备环境了。
            //a.需要等待一堆线程中的某一个线程执行结束,马上触发一个动作;
            //解决方案: Task.WaitAny--等待几个线程中的某一个线程执行结束;---主线程会等待---会卡顿界面;一直到某一个线程执行结束后,才往后执行;--体验不好 
            //4.如果所有人开发完毕了,庆祝一下,一起吃个饭;

            //三、应用场景:
            //1.ContinueWhenAny
            //如果需要在一堆任务中,某一种执行结束后,去触发一个动作;


            //2.ContinueWhenAll
            //如果需要回调---如果需要控制顺序:

            //3.WaitAny
            //   有一个列表数据:有可能是来自于第三方接口,有可能是来自于缓存,也有可能是来自于数据库,查询的时候,我们不确定;
            // 常规玩法: 先找缓存,如果有数据,直接返回了,如果缓存没有--可能要去查询数据库,如果数据库有数据,直接返回,如果没有---查询第三方接口;
            // 多线程:同时开启三个线程,同时去查询三个地方的数据,只要是有一个地方的数据查询到了,只要是有一个地方的数据找到了,其他的两个线程我们就不管了;直接把找到的数据返回给前端就可以了;
            //
            //
            //4.WaitAll
            // 如果有一个首页,首页中包含了很多功能:考勤信息,年度top10,季度top10,公告,通知;
            // 在主页中:要加载主页-这些信息都需要查询出来: 而且这些信息都是来自于不同的地方,有的来自于接口,有的来自于缓存有的都来于数据库: 
            //有几个块信息,就开启几个线程,同时分别去各自的地方进行查询各自的数据;可以在后台等待所有的子线程执行结束;拿到结果、组件一个大的复杂实体对象,传递给视图,通过视图做绑定;--让查询并发执行: 但是这里如果是使用C#开发,不做前后端分离的话,可以考虑这种,可以提高性能;
            //现在更多的时候,可能是使用异步Ajax来完成---用户体验会更好;  资源会有所浪费,但是性能可以提高;


            {
                Debug.WriteLine("第15期高级班课程起飞。。。");
                Debug.WriteLine("Richard老师开始讲课了。。。。");
                this.Teach("跨平台开发.NET5");
                this.Teach("高并发组件Redis/Nginx/RabbitMQ/Memcache/Mongo...");
                this.Teach("各种框架扩展定制。。。。");
                Debug.WriteLine("Richard老师知识点已经讲完了。。。。。");
                Debug.WriteLine("开始项目实战----直播平台实战课");

                List<Task> taskList = new List<Task>();
                TaskFactory factory = new TaskFactory();
                taskList.Add(factory.StartNew(obj => Coding("嘟嘟", "权限的数据库设计"), "嘟嘟"));
                taskList.Add(factory.StartNew(obj => Coding("年轻人不讲武德", "WeChat接口对接"), "年轻人不讲武德"));
                taskList.Add(factory.StartNew(obj => Coding("闻", "脚手架框架搭建"), "闻"));
                taskList.Add(factory.StartNew(obj => Coding("超越", "ABPVNetxt框架搭建"), "超越"));
                taskList.Add(factory.StartNew(obj => Coding("角印", "编写Webapi"), "角印"));

                {
                    //相当于是一个回调;主线程执行的时候,这里是不卡段界面的;当taskList集合中的某一个线程执行结束语了;就触发后面委托中的动作;---不卡顿界面--用户体验就更好
                    factory.ContinueWhenAny(taskList.ToArray(), ts =>
                    {
                        Debug.WriteLine($"{ts.AsyncState}同学开发完毕,Richard老师开始准备环境。。。");
                    });

                    //
                }
                {
                    factory.ContinueWhenAll(taskList.ToArray(), ts =>
                    {
                        Debug.WriteLine($"所有人开发完毕,我们一起庆祝一下,一起吃个饭!");
                    });
                }

                {
                    //Task.WaitAny--等待几个线程中的某一个线程执行结束;---主线程会等待-- - 会卡顿界面;一直到某一个线程执行结束后,才往后执行;--体验不好
                    Task.WaitAny(taskList.ToArray());//主线程等待,其中某一个线程执行结束,然后继续往后执行;
                    Debug.WriteLine("xxxx同学开发完毕,Richard老师开始准备环境。。。");
                }
                {
                    //Task.WaitAll--等待几个线程都执行结束;---主线程会等待-- 一直到所有的线程执行结束,才往后执行;- 会卡顿界面;--体验不好
                    Task.WaitAny(taskList.ToArray());//主线程等待,其中某一个线程执行结束,然后继续往后执行;
                    Task.WaitAll(taskList.ToArray());
                    Debug.WriteLine($"所有人开发完毕,我们一起庆祝一下,一起吃个饭!");
                }

                List<Action> actions = new List<Action>();
                actions.Add(() => { });
                actions.Add(() => { });
                actions.Add(() => { });
                actions.Add(() => { });
                actions.Add(() => { });
                actions.Add(() => { });
                actions.Add(() => { });

                ParallelOptions options = new ParallelOptions();
                options.MaxDegreeOfParallelism = 2; //下面在开启线程执行委托的时候,最多开启2个线程;

                Parallel.Invoke(options,actions.ToArray()); //会开启四个线程分别去执行;
                //如果想要限制线程数量
            }
            Debug.WriteLine($"****************btnTask_Click End || 线程ID:  {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
        }



        //现在是22:06,大家就开始提问&&休息,22:10,开始答疑!期间老师不说话了


        #region Private Method
        /// <summary>
        /// 模拟了讲课的过程:
        /// </summary>
        /// <param name="lesson"></param>
        private void Teach(string lesson)
        {
            Debug.WriteLine($"{lesson} ||开始了。。。");
            long lResult = 0;
            //for (int i = 0; i < 1_000_000_000; i++)
            //{
            //    lResult += i;
            //}
            Debug.WriteLine($"{lesson} || 讲完了。。。");
        }
        /// <summary>
        /// 模拟Coding过程
        /// </summary>
        /// <param name="name"></param>
        /// <param name="projectName"></param>
        private void Coding(string name, string projectName)
        {
            Debug.WriteLine($"****************Coding Start  || {name} {projectName}  {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
            long lResult = 0;
            for (int i = 0; i < 1_000_000_000; i++)
            {
                lResult += i;
            }
            Thread.Sleep(3000);
            Debug.WriteLine($"****************Coding   End ||  {name} {projectName} {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")} {lResult}***************");
        }
        #endregion


    }
}

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace MyThreadDemo
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }




        //同步异步:
        #region MyRegion
        //1. 进程/线程/多线程
        //2. 同步异步
        //3. 异步的三大特点
        //4. C#中的多线程

        //一、进程:计算机概念,虚拟的记录,描述一个应用程序在计算机上运行的时候,所消耗的各种资源的集合---Cpu+内容+磁盘IO+网络资源;
        //---类似于某一个公司---公司正常运作;

        //二、线程:(计算机资源)一个程序的进程中,所执行的具体的某一个动作的最小执行流;小到点击某个按钮,大到通过网络发送一句话出去;
        //具体到某一个人:
        //进程必然是包含了多个线程;线程是依附于进程存在的;如果进程不在了,线程也随之消失了;


        //三、句柄:是一个long了类型的数字,对应这计算机程序中的某一个小部件;要操作程序,对应的最小的单位;
        //公司中的任何一个物件--编号--计算机---会给计算机坐个编号---(部门---座位号)

        //四、为什么计算机可以多线程?跟计算机的CPU的核数有关;
        //6核12线程:把六个核心进行逻辑切分:如果有动作需要计算机响应,操作系统就会去申请CPU来处理;CPU在执行动作的时候,CPU是分片执行:
        //分片:把每一个核每一毫秒可以执行的动作,切分成10000份;操作系统在调度的时候,执行动作,切分后去执行的多个动作的时候;开始动作A,使用的是分片后的某一份;  结束的时候,可能使用的是另外的某一份; 
        //计算机在不断的调度过程中;
        //1.从宏观角度来说:多个动作,就可以做到在某一段时间内;看似同时执行完毕了;
        //2.从微观的角度来说:某一时刻,同意时刻只能处理一件事儿--串行执行;

        //五、C#中的多线程:Thread/ThreadPool/Task 都是C#语言在操作计算机的资源(线程)时;封装的一个帮助类库;
        //线程:---同步异步:
        //单线程执行代码命令:同步执行;
        //同步方法:
        //1.线性执行,从上往下依次执行--很符合我们人类的思维逻辑,线程ID为01  (主线程/UI线程)
        // 请人吃饭:真心的请人吃饭;Richard老师请Vn吃饭;说:Vn,晚上一起去吃饭;Vn:我还要忙一会儿,Richard:那好,我等你;等你忙完,我们一起去吃饭;
        //2.同步方法执行慢;卡顿界面--只有一个线程参与计算---CPU太忙,根本无暇他顾;只有一个线程执行动作; 消耗的计算机资源少(工钱少)
        //3.同步方法:有序执行;


        //多线程执行代码命令:异步执行:
        //异步方法:
        //1.开启了一个新的线程(多线程--子线程)(有一个新的线程Id);且不再是线型执行了;  UI线程不等待子线程执行完毕;主线程直接往后执行;  子线程延迟执行 
        //请人吃饭:客气一下请人吃饭:Richard老师客气一下请人Vn吃饭,说:Vn,晚上一起吃饭,Vn:我还要忙一会儿,Richard:那你先忙吧,我就先去吃饭了,你忙完自己去吃饭吧!
        //2.异步方法执行快:不卡顿界面;开启了一个新的线程去执行去了;开启了五个线程去执行动作:消耗的计算机资源多(工钱多)
        //  异步方法--多线程方法--以资源换时间; 使用大量的资源,降低时间成本;
        //3.无序执行:线程开启无法控制谁先谁后;线程执行计算结束也无法控制谁先谁后;---多线程异步执行:无序执行;


        #endregion
        //Thread
        //ThreadPool
        //Task
        /// <summary>
        /// 同步方法
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnSync_Click(object sender, EventArgs e)
        {
            Debug.WriteLine($"****************btnSync_Click Start {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");

            for (int i = 0; i < 5; i++)
            {
                DoSomething("kulala");
            }

            Debug.WriteLine($"****************btnSync_Click End   {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
        }

        /// <summary>
        /// 异步方法
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnAsnyc_Click(object sender, EventArgs e)
        {
            Debug.WriteLine($"****************btnAsyncAdvanced_Click Start {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");

            #region 委托异步调用
            //在ASP.NET Core的年代:BeginInvoke不再支持了;如果想要看看这个,可以参考第14期;
            //Action<string> action = this.DoSomething;
            //AsyncCallback asyncCallback = null;
            //action.BeginInvoke(" Richard ", asyncCallback, "Object");
            #endregion

            //Task开启了一个线程 
            for (int i = 0; i < 5; i++)
            {
                Task.Run(() =>
                {
                    DoSomething("kulala");
                });
            }

            Debug.WriteLine($"****************btnAsyncAdvanced_Click End   {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
        }

        #region Private Method

        /// <summary>
        /// 一个比较耗时耗资源的私有方法
        /// </summary>
        /// <param name="name"></param>
        private void DoSomething(string name)
        {
            Debug.WriteLine($"****************DoSomething Start  {name}  {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
            long lResult = 0;
            for (int i = 0; i < 1000_000_000; i++)
            {
                lResult += i;
            }
            //Thread.Sleep(2000);
            Debug.WriteLine($"****************DoSomething   End  {name}  {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")} {lResult}***************");
        }


        #endregion


        /// <summary>
        /// Task:
        /// 
        ///在最老版本中,有Thread/ThreadPool
        ///在前几天,在QQ大群有相关的公告的,你们下载观看
        ///1..NetFramework3.0时代实现
        ///2.C#中多线程操作的最佳实现---丰富的Api,我们在开发中遇到个各种场景,他都可以满足到;3.Task操作的线程来自于线程/池  
        ///Task,Prallel他们所操作的线程都是来自于线程池;
        /// 
        ///确定线程的标识:线程Id,线程Id不一样,线程其实就是不同的线程;
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>

        private void btnTask_Click(object sender, EventArgs e)
        {
            Debug.WriteLine($"****************btnTask_Click Start|| 线程ID: {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
            //一、Task开启线程有哪些方式:
            #region MyRegion
            {
                //Task task = new Task(new Action(() =>
                //{
                //    Debug.WriteLine("欢迎大家来到.NET高级班进阶学习");
                //    this.DoSomething("Richard");
                //}));
                //task.Start();//线程开启了
            }
            {
                //    Task.Run(() =>
                //    {
                //        this.DoSomething("Richard");
                //    });

                //    Task.Run<int>(() =>
                //    {
                //        return DateTime.Now.Year;
                //    });
            }
            {
                //    TaskFactory factory = Task.Factory;
                //    factory.StartNew(() =>
                //    {
                //        this.DoSomething("一意");
                //    });
            }
            {
                //TaskFactory factory = new TaskFactory();
                //Task<int> tTask = factory.StartNew<int>(() => DateTime.Now.Year);
            }
            #endregion

            //父子级线程
            //一个Task内部,开启了几个线程以后;Task内部的线程可以理解为子线程;
            //父线程在等待的时候,子线程没有线程等待;子线程可能内容还没有执行万一,父线程就已经结束了;
            {
                Task task = new Task(() =>
                {
                    Debug.WriteLine($"****************task开始了: {Thread.CurrentThread.ManagedThreadId.ToString("00")} ***************");
                    Task task1 = new Task(() =>
                    {
                        Debug.WriteLine($"****************task1: {Thread.CurrentThread.ManagedThreadId.ToString("00")} ***************");
                        Thread.Sleep(1000);
                        Debug.WriteLine("我是task1线程");
                    });

                    Task task2 = new Task(() =>
                    {
                        Debug.WriteLine($"****************task2: {Thread.CurrentThread.ManagedThreadId.ToString("00")} ***************");
                        Thread.Sleep(1000);
                        Debug.WriteLine("我是task2线程");
                    });
                    task1.Start();
                    task2.Start();

                    //task1.Wait();
                    //task2.Wait();

                    Debug.WriteLine($"****************task: {Thread.CurrentThread.ManagedThreadId.ToString("00")} ***************");
                });
                task.Start();//线程启动了
                task.Wait();   //单个线程的等待;等待task 内部的内容执行完毕,这里会卡顿界面;是主线程等待;

                // task.Wait();//等待执行完成:
                task.Wait(TimeSpan.FromMilliseconds(1100));
                task.Wait(1000);//限时等待;过时不候

                // Thread thread = null;

                //thread.Abort();//线程停止;
                //thread.Start();
                //thread.IsBackground = true;//后台线程:进程结束,线程随之消失
                //thread.IsBackground = false;//前台线程:进程结束,线程把内部需要执行的动作执行完毕,然后消失

            }

            //TaskCreationOptions.PreferFairness 相对来说比较公平执行的:如果是先申请的线程,就会优先执行;
            {
                //Task task1= new Task(() =>
                //{

                //}, TaskCreationOptions.PreferFairness);

                //Task task2 = new Task(() =>
                //{

                //}, TaskCreationOptions.PreferFairness);

            }
            {
                //    {
                //        Stopwatch stopwatch = new Stopwatch();
                //        stopwatch.Start();
                //        Thread.Sleep(3000);//主线程执行到这儿会卡顿等待;等待3000ms后继续往后;   
                //        stopwatch.Stop();
                //        Debug.WriteLine($"Thread.Sleep(3000):{stopwatch.ElapsedMilliseconds}");
                //    }
                //    {
                //        Stopwatch stopwatch = new Stopwatch();
                //        stopwatch.Start(); 
                //        //回调:Delay一般和ContinueWith配合使用;
                //        //不卡顿界面:3000ms以后,去执行一段业务逻辑:执行的动作就是ContinueWith内部的委托;ContinueWith内部的执行有可能是一个全新的线程去执行,也有可能是主线程去执行; 
                //        Task.Delay(3000).ContinueWith(t =>
                //        {
                //            Debug.WriteLine($"****************Delay || 线程ID:  {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
                //            stopwatch.Stop();
                //            Debug.WriteLine($"Task.Delay(3000):{stopwatch.ElapsedMilliseconds}");
                //        });//一般情况下,这个Delay 是等待3000ms继续做点什么---或者说延迟3000ms后做点什么; 
                //    }
            }

            //现在是20:56,大家休息5分钟&&上厕所,21:01继续~~
            //
            //多线程:他的应用场景:
            //一、在什么情况下,可以使用多线程?
            //1.一个数据库查询:---可以使用多线程吗?不适合使用多线程;因为只有一个动作;不存在多个动作并发执行;
            //2.如果要同时去查询接口+查询缓存+查询数据库?--适合使用多线程吗?---可以开启三个线程;每个线程就负责一个动作; 
            //通过一个案例,来解析: 

            //二、高级班VIP课程讲课:
            //1.开始上课---Richard老师开始讲课--一节一节的开始讲:适合使用多线程吗?--不适合:不能同时讲多个课
            //。。。。。经过大概8个月的时间
            //2.开始项目实战---分组进行;多人合作完成; 适合使用多线程吗? ---适合;每个人就可以对应一个线程;多个人同时去开发功能---多线程并发;

            //3.如果大家其中有一个人完成了功能的开发,Richard老师就要开始准备环境了。
            //a.需要等待一堆线程中的某一个线程执行结束,马上触发一个动作;
            //解决方案: Task.WaitAny--等待几个线程中的某一个线程执行结束;---主线程会等待---会卡顿界面;一直到某一个线程执行结束后,才往后执行;--体验不好 
            //4.如果所有人开发完毕了,庆祝一下,一起吃个饭;

            //三、应用场景:
            //1.ContinueWhenAny
            //如果需要在一堆任务中,某一种执行结束后,去触发一个动作;


            //2.ContinueWhenAll
            //如果需要回调---如果需要控制顺序:

            //3.WaitAny
            //   有一个列表数据:有可能是来自于第三方接口,有可能是来自于缓存,也有可能是来自于数据库,查询的时候,我们不确定;
            // 常规玩法: 先找缓存,如果有数据,直接返回了,如果缓存没有--可能要去查询数据库,如果数据库有数据,直接返回,如果没有---查询第三方接口;
            // 多线程:同时开启三个线程,同时去查询三个地方的数据,只要是有一个地方的数据查询到了,只要是有一个地方的数据找到了,其他的两个线程我们就不管了;直接把找到的数据返回给前端就可以了;
            //
            //
            //4.WaitAll
            // 如果有一个首页,首页中包含了很多功能:考勤信息,年度top10,季度top10,公告,通知;
            // 在主页中:要加载主页-这些信息都需要查询出来: 而且这些信息都是来自于不同的地方,有的来自于接口,有的来自于缓存有的都来于数据库: 
            //有几个块信息,就开启几个线程,同时分别去各自的地方进行查询各自的数据;可以在后台等待所有的子线程执行结束;拿到结果、组件一个大的复杂实体对象,传递给视图,通过视图做绑定;--让查询并发执行: 但是这里如果是使用C#开发,不做前后端分离的话,可以考虑这种,可以提高性能;
            //现在更多的时候,可能是使用异步Ajax来完成---用户体验会更好;  资源会有所浪费,但是性能可以提高;


            {
                Debug.WriteLine("第15期高级班课程起飞。。。");
                Debug.WriteLine("Richard老师开始讲课了。。。。");
                this.Teach("跨平台开发.NET5");
                this.Teach("高并发组件Redis/Nginx/RabbitMQ/Memcache/Mongo...");
                this.Teach("各种框架扩展定制。。。。");
                Debug.WriteLine("Richard老师知识点已经讲完了。。。。。");
                Debug.WriteLine("开始项目实战----直播平台实战课");

                List<Task> taskList = new List<Task>();
                TaskFactory factory = new TaskFactory();
                taskList.Add(factory.StartNew(obj => Coding("嘟嘟", "权限的数据库设计"), "嘟嘟"));
                taskList.Add(factory.StartNew(obj => Coding("年轻人不讲武德", "WeChat接口对接"), "年轻人不讲武德"));
                taskList.Add(factory.StartNew(obj => Coding("闻", "脚手架框架搭建"), "闻"));
                taskList.Add(factory.StartNew(obj => Coding("超越", "ABPVNetxt框架搭建"), "超越"));
                taskList.Add(factory.StartNew(obj => Coding("角印", "编写Webapi"), "角印"));

                {
                    //相当于是一个回调;主线程执行的时候,这里是不卡段界面的;当taskList集合中的某一个线程执行结束语了;就触发后面委托中的动作;---不卡顿界面--用户体验就更好
                    factory.ContinueWhenAny(taskList.ToArray(), ts =>
                    {
                        Debug.WriteLine($"{ts.AsyncState}同学开发完毕,Richard老师开始准备环境。。。");
                    });

                    //
                }
                {
                    factory.ContinueWhenAll(taskList.ToArray(), ts =>
                    {
                        Debug.WriteLine($"所有人开发完毕,我们一起庆祝一下,一起吃个饭!");
                    });
                }

                {
                    //Task.WaitAny--等待几个线程中的某一个线程执行结束;---主线程会等待-- - 会卡顿界面;一直到某一个线程执行结束后,才往后执行;--体验不好
                    Task.WaitAny(taskList.ToArray());//主线程等待,其中某一个线程执行结束,然后继续往后执行;
                    Debug.WriteLine("xxxx同学开发完毕,Richard老师开始准备环境。。。");
                }
                {
                    //Task.WaitAll--等待几个线程都执行结束;---主线程会等待-- 一直到所有的线程执行结束,才往后执行;- 会卡顿界面;--体验不好
                    Task.WaitAny(taskList.ToArray());//主线程等待,其中某一个线程执行结束,然后继续往后执行;
                    Task.WaitAll(taskList.ToArray());
                    Debug.WriteLine($"所有人开发完毕,我们一起庆祝一下,一起吃个饭!");
                }

                List<Action> actions = new List<Action>();
                actions.Add(() => { });
                actions.Add(() => { });
                actions.Add(() => { });
                actions.Add(() => { });
                actions.Add(() => { });
                actions.Add(() => { });
                actions.Add(() => { });

                ParallelOptions options = new ParallelOptions();
                options.MaxDegreeOfParallelism = 2; //下面在开启线程执行委托的时候,最多开启2个线程;

                Parallel.Invoke(options, actions.ToArray()); //会开启四个线程分别去执行;
                //如果想要限制线程数量
            }
            Debug.WriteLine($"****************btnTask_Click End || 线程ID:  {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
        }



        #region Private Method
        /// <summary>
        /// 模拟了讲课的过程:
        /// </summary>
        /// <param name="lesson"></param>
        private void Teach(string lesson)
        {
            Debug.WriteLine($"{lesson} ||开始了。。。");
            long lResult = 0;
            //for (int i = 0; i < 1_000_000_000; i++)
            //{
            //    lResult += i;
            //}
            Debug.WriteLine($"{lesson} || 讲完了。。。");
        }
        /// <summary>
        /// 模拟Coding过程
        /// </summary>
        /// <param name="name"></param>
        /// <param name="projectName"></param>
        private void Coding(string name, string projectName)
        {
            Debug.WriteLine($"****************Coding Start  || {name} {projectName}  {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
            long lResult = 0;
            for (int i = 0; i < 1_000_000_000; i++)
            {
                lResult += i;
            }
            Thread.Sleep(3000);
            Debug.WriteLine($"****************Coding   End ||  {name} {projectName} {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")} {lResult}***************");
        }

        #endregion

        /// <summary>
        /// Parallel
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnParallel_Click(object sender, EventArgs e)
        {

            //如果我需要一次开启多个线程来执行一部分动作呢?

            Debug.WriteLine($"****************btnParallel_Click Start || 线程ID:  {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
            {
                {
                    //List<Action> acitonList = new List<Action>();
                    //acitonList.Add(() => { });
                    //acitonList.Add(() => { });
                    //acitonList.Add(() => { });
                    //Parallel.Invoke(acitonList.ToArray());//也是可以开启线程,可以一次放入很多个委托去执行;
                }
                //一、Parallel
                //1.可以传入多个委托
                //2.多个委托中的内容是会开启线程来执行---执行这里的线程有可能是新的线程,也有可能是主线程参与计算的
                //3.会阻塞主线程---相当于是主线程等待子线程执行结束

                {
                    ParallelOptions options = new ParallelOptions();
                    options.MaxDegreeOfParallelism = 3;
                    Parallel.Invoke(options,
                        () =>
                        {
                            Debug.WriteLine($"线程ID:  {Thread.CurrentThread.ManagedThreadId.ToString("00")}");
                            this.DoSomething("this is Action 01");
                        },
                        () =>
                        {
                            Debug.WriteLine($"线程ID:  {Thread.CurrentThread.ManagedThreadId.ToString("00")}");
                            this.DoSomething("this is Action 02");
                        },
                        () =>
                        {
                            Debug.WriteLine($"线程ID:  {Thread.CurrentThread.ManagedThreadId.ToString("00")}");
                            this.DoSomething("this is Action 03");
                        });
                }
                //二、能不能然他不阻塞界面?包一个Task
                {
                    //Task.Run(() =>
                    //{ 
                    //    Parallel.Invoke(
                    //  () =>
                    //  {
                    //      Debug.WriteLine($"线程ID:  {Thread.CurrentThread.ManagedThreadId.ToString("00")}");
                    //      this.DoSomething("this is Action 01");
                    //  },
                    //  () =>
                    //  {
                    //      Debug.WriteLine($"线程ID:  {Thread.CurrentThread.ManagedThreadId.ToString("00")}");
                    //      this.DoSomething("this is Action 02");
                    //  },
                    //  () =>
                    //  {
                    //      Debug.WriteLine($"线程ID:  {Thread.CurrentThread.ManagedThreadId.ToString("00")}");
                    //      this.DoSomething("this is Action 03");
                    //  });
                    //});
                }
                //三、还不是开启了多个线程去执行委托?有啥作用:--Parallel是基于Task一个封装;
                //1.既然是开启多个线程--Parallel.For
                //2.如果有一大堆的任务要执行;100个任务---需要多线来执行:100个任务---开启100个线程?--不好
                //2.控制线程的数量---Parallel就是可以控制线程的数量,不至于出现线程泛滥的情况
                //

                {
                    ParallelOptions options = new ParallelOptions();
                    options.MaxDegreeOfParallelism = 3;
                    Parallel.For(0, 100, options, index =>
                     {
                         Debug.WriteLine($"index:{ index}  线程ID:  {Thread.CurrentThread.ManagedThreadId.ToString("00")}");
                         this.DoSomething("this is Action 03");
                     });
                }
                {
                    List<int> intlist = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 };  //100个
                                                                                                                        //100个任务: 如果我使用Parallel来开启线程计算;线程会有100个线程来执行--线程数量会过多;
                                                                                                                        //1.最好能够控制线程数量   100个任务;  限定开启5个线程;控制反正一共就只有五个线程参与计算
                                                                                                                        //2.相当于5个线程去平摊这100个任务---既开启了多个线程来执行任务---提高性能---且没有过多的开启线程(过多的开启线程会过多的损耗计算机的资源);

                    ParallelOptions options = new ParallelOptions();
                    options.MaxDegreeOfParallelism = 3;    //会有17个任务,限定了3个线程去执行这17个任务
                    Parallel.ForEach(intlist, options, s =>
                    {
                        Debug.WriteLine($"index:{ s}  线程ID:  {Thread.CurrentThread.ManagedThreadId.ToString("00")}");
                        this.DoSomething("this is Action 03");
                    });
                }
            }

            Debug.WriteLine($"****************btnParallel_Click End || 线程ID:  {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
        }

        /// <summary>
        /// task进阶
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void TsakAdvanced_Click(object sender, EventArgs e)
        {

            Debug.WriteLine($"****************TsakAdvanced_Click start || 线程ID:  {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
            //一、多线程中的异常情况
            //1.你们在开发中,如果要捕捉异常---普通方法--try-catch
            //2.多线程中,如果发生异常,使用try-catch包裹,捕捉不到异常
            //3.异常去哪儿了呢?  异常肯定是被吞掉了
            //4.多线程中,如果要捕捉异常---怎么做?
            //5.多线程中,如果要捕捉异常,需要设置主线程等待子线程执行结束;可以捕捉到异常
            //6.多线程内部发生异常后,抛出的异常类型是:system.AggregateException(多线程的异常类型)
            //7.如果(try-catch--catch)给定多个异常类型类匹配,多线程中,异常之后,有限配具体,如果没有具体,再匹配抽象
            {
                try
                {
                    {
                        //Task task = Task.Run(() =>
                        // {
                        //     int i = 0;
                        //     int j = 10;
                        //     int k = j / i; //尝试除以0  会异常
                        // });

                        //List<Task> tasks = new List<Task>();
                        //tasks.Add(task);
                        //Task.WaitAll(tasks.ToArray()); 
                    }

                    List<Task> tasklist = new List<Task>();
                    for (int i = 0; i < 20; i++)
                    {
                        string keywork = $"TsakAdvanced_Click_{i}";
                        tasklist.Add(Task.Run(() =>
                       {
                           Thread.Sleep(new Random().Next(50, 100));
                           if (keywork == "TsakAdvanced_Click_6")
                           {
                               throw new Exception("TsakAdvanced_Click_6");
                           }
                           else if (keywork == "TsakAdvanced_Click_9")
                           {
                               throw new Exception("TsakAdvanced_Click_9");
                           }
                           else if (keywork == "TsakAdvanced_Click_12")
                           {
                               throw new Exception("TsakAdvanced_Click_12");
                           }
                       }));
                    }
                    Task.WaitAll(tasklist.ToArray());

                }
                catch (AggregateException aex) //具体
                {
                    Debug.WriteLine(aex.Message);
                    foreach (var exception in aex.InnerExceptions)
                    {
                        Console.WriteLine(exception.Message);
                    }
                }
                catch (Exception ex) //父类(一切异常的父类) 抽象
                {
                    Debug.WriteLine(ex.Message);
                }
            }

            //故事、如果三个线程去执行一个业务逻辑体(查询---线程1--执行修改数据库;线程2---执行修改缓存,线程三--执行一个调用接口去修改另外一个服务器上的数据)
            //以上这个逻辑体执行过程中,如果有一个线程是异常了;在这个逻辑体中,其实就是一个残缺的--表示整个逻辑就有问题! 
            //多线程执行的时候,有时候,必须是多个线程都执行成功,才算成功,只要有一个线程异常了,就表示都异常----既然都是异常了,就应该让线程取消;已经异常了,就没哟必须继续往后了

            //二、线程取消;  线程是无法从外部取消的(除非关闭进程),只能自己取消自己---只有上帝才能打败上帝;
            //1.线程如何自己取消自己呢?----线程自己取消---其实就是向外抛出一个异常了; 
            //关于Thread/ThreadPool  看过录播的刷个1   否则刷个2 
            //2.如何取消线程呢?---具体场景中,应该怎么做呢?
            //3.标准的线程取消
            // a) 实例化一个 CancellationTokenSource 
            // b)  包含了一个IsCancellationRequested 属性,属性值默认为false
            // c)  包含了一个Cancel方法--Cancel 方法如果被执行--CancellationTokenSource 内部的属性值马上---false--true; 且只能从  false--true  不能由true --false
            //cts线程取消--看哪个线程跑的慢,如果有一个线程发生了异常了,跑的慢的线程,就会被取消掉(异常掉),如果跑的都比较快的线程--当还没有线程发生异常的时候,这个比较快的线程已经结束了,那么这个结束的线程是无法被取消的;

            //4. 当有一个线程发生异常的时候,其他线程就会有三种情况 1.已经结束的线程--不管(管不住); 2.已经正常开始,我可以让你取消,让这线程在结束的时候,抛出异常(取消了);3.还有部分的线程根本都还没有开启:只要有异常的线程,就应该让没有开启的线程不再开启了
            //


            {
                //Thread thread = null;
                //thread.Abort(); //取消线程
            }
            {
                //Task task = Task.Run(() =>
                // {
                //     int i = 0;
                //     int j = 10;
                //     int k = j / i; //尝试除以0  会异常
                // });

                //List<Task> tasks = new List<Task>();
                //tasks.Add(task);
                //Task.WaitAll(tasks.ToArray()); 
            }

            try
            {
                List<Task> tasks = new List<Task>();
                CancellationTokenSource cts = new CancellationTokenSource();
                for (int i = 0; i < 100; i++)
                {
                    string keywork = $"TsakAdvanced_Click_{i}";
                    tasks.Add(Task.Run(() =>
                    {
                        Thread.Sleep(new Random().Next(10, 300));
                        //if (cts.IsCancellationRequested == false)
                        //{
                        //    Debug.WriteLine($" 线程ID:  {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")} 正常开始了");
                        //}
                        //else
                        //{
                        //    Debug.WriteLine($" 线程ID:  {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")} 没有正常开始了");
                        //    //throw new Exception($"{Thread.CurrentThread.ManagedThreadId.ToString("00") }取消了。。。");
                        //}
                        cts.Token.ThrowIfCancellationRequested();


                        try
                        {
                            if (keywork == "TsakAdvanced_Click_6")
                            {
                                throw new Exception("TsakAdvanced_Click_6");
                            }
                        }
                        catch (Exception)
                        {
                            cts.Cancel();
                        }





                        cts.Token.ThrowIfCancellationRequested();


                        //if (cts.IsCancellationRequested == false)
                        //{
                        //    Debug.WriteLine($" 线程ID:  {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")} 正常结束了。。。");
                        //}
                        //else
                        //{ 

                        //    Debug.WriteLine($" 线程ID:  {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")} 没有正常结束了。。。");
                        //    //throw new Exception($"{Thread.CurrentThread.ManagedThreadId.ToString("00") }取消了。。。" );
                        //}
                    }, cts.Token)); //有线程发生异常后,还没有开启的线程就不再开启了
                }
                Task.WaitAll(tasks.ToArray());
            }
            catch (AggregateException aex)
            {
                foreach (var exception in aex.InnerExceptions)
                {
                    Debug.WriteLine(exception.Message);
                } 
            } 

            Debug.WriteLine($"****************TsakAdvanced_Click End || 线程ID:  {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

是刘彦宏吖

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值