6: Thread and ThreadPool (thread and thread pool) and the past and present of threads

table of Contents

Preface

由于这一部分内容,之前工作用到过,算是比较熟,但是总结嘛。放我的有点精简了,还是把老师的晾上来吧!

1.Thread

		///进程:计算机概念,程序在运行的时候,记录当前程序对计算机的各种资源的消耗的一种记录;虚拟出来;
        ///线程:也是计算机概念;线程是计算机在执行某一个动作的时候,一个最小的执行流,虚拟出来的一个代名词;
        ///包含关系:一个进程包含多个线程;
        ///句柄:句柄其实就是一个数字--对标与计算机程序中的一个最小单位;Id,long类型的数字;


        //C#中的多线程:Thread是对计算机资源操作一种封装类;
        //为什么可以多线程?
        //1.多个CPU可有有多个核可以并行计算;
        //8核16线程,线程其实是模拟出来;
        //计算机的计算能力超强的;一个线程去操作某一个计算;
        //2.CPU分片 1s 能处理1000000次计算;把1s内的处理能力再进一步切分; 操作系统去调用执行不同的计算;
        //  从宏观来讲: 就相当于有很多个任务可以去并发执行;
        //  从微观来讲:一个物理CPU同一时刻,只能为一个任务服务;


        //同步异步:
        //同步方法:发起调用,代码执行一行一行的来,按照顺序执行;非常符合我们的开发思维;------有顺序(线程ID是同一个--同一个线程来执行的所有操作);
        //请人吃饭:诚心诚意的请人吃饭,邀请 “我要上台” 吃饭,“我要上台”:我现在有点忙,我等你,你忙完以后,我俩一起去吃饭;

        //异步方法:发起调用:没有等待完成,直接进入到下一行,启动一个新的线程来执行动作(线程ID不一样);
        // 请人吃饭:只是客气一下的请人吃饭,邀请 “我要上台” 吃饭,“我要上台”:我现在有点忙,那先先忙吧,我就先去吃饭了,你忙完自己去吃呗;


        //异步方法三大特点:
        //1.不卡顿界面:UI线程(主线程)闲置,计算任务都交给子线程去执行了;
        //同步方法:卡界面,因为主线程忙于计算,根本无暇他顾;
        //改善了用户体验了;场景:发送短信、发送邮件;

        //2.同步方法慢,异步方法快;因为多线程并发:以资源换性能;
        //同步方法:10s
        //异步方法:2.3s  
        //中间相差了大概五倍;达不到五倍;因为线程的调度也需要消耗资源;
        //到不到5倍:CPU密集型计算(资源受限)

        //同步方法:10.01s
        //异步方法:2.0001s    下面这组更加接近5倍
        //Thread.Sleep 不消耗资源,只是等待;

        //3.同步方法按顺序执行,异步方法无序性;
        //启动无顺序:线程资源是向操作系统申请的,有操作系统的调度策略来决定;所以启动顺序随机的;
        //执行也是无顺序;
        //通过以上两点:结束当然也是无顺序的;


        //难道就不能控制顺序吗?
        //其实也可以;

        /// <summary>
        /// 同步方法
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnSync_Click(object sender, EventArgs e)
        {
    
    
            //Thread.CurrentThread.ManagedThreadId 对标于每一个线程的一个ID;
            Console.WriteLine($"****************btnSync_Click Start {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
            int l = 3;
            int m = 4;
            int n = l + m;
            for (int i = 0; i < 5; i++)
            {
    
    
                string name = string.Format($"btnSync_Click_{i}");
                this.DoSomethingLong(name);
            }
            Console.WriteLine($"****************btnSync_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 DoSomethingLong(string name)
        {
    
    
            Console.WriteLine($"****************DoSomethingLong 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); //线程是闲置的;
            Console.WriteLine($"****************DoSomethingLong   End  {name}  {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")} {lResult}***************");
        }
        #endregion


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

            Action<string> action = this.DoSomethingLong;
            action.Invoke("btnAsync_Click");
            action("btnAsync_Click");

            action.BeginInvoke("btnAsync_Click", null, null); //会分配一个新的线程去执行;20200803Core还不支持;

            for (int i = 0; i < 5; i++)
            {
    
    
                string name = string.Format($"btnAsync_Click_{i}");
                action.BeginInvoke(name, null, null);
            }
            Console.WriteLine($"****************btnAsync_Click End   {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
        }

        /// <summary>
        /// C#中的多线程
        ///Thread:.Netframework1.0  在.NetCore年代,依然支持;
        ///Thread:是C#语言对计算机资源线程操作的一个封装类;
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnThread_Click(object sender, EventArgs e)
        {
    
    
            Console.WriteLine($"****************btnThread_Click Start   {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
            {
    
    
                //ThreadStart method = () =>
                //{
    
    
                //    Thread.Sleep(3000);
                //    this.DoSomethingLong("btnThread_Click");
                //    Thread.Sleep(3000);
                //};

                //Thread thread = new Thread(method);
                //thread.Start(); 
                {
    
    
                    不靠谱,其实做不到马上停止、马上暂停
                    //thread.Suspend();//挂起、暂停
                    //thread.Resume(); //恢复暂停的线程 
                    //thread.Abort();//停止  对外抛出ThreadAbortException异常
                    //Thread.ResetAbort();//让停止的线程继续允许 
                    就可以通过判断状态来做到线程等待
                    1.等待
                    //while (thread.ThreadState!=ThreadState.Stopped)
                    //{
    
    
                    //    Thread.Sleep(100);
                    //}
                    2.Join 等待
                    //thread.Join();//主线程等待子线程计算完成;卡界面
                    //thread.Join(2000);//等待2000ms,过时不候;
                    //thread.Priority = ThreadPriority.Normal;  //线程优先级,其实是提高优先执行的概率;有意外;优先执行并不代表优先结束; 千万不要用这个来控制线程的执行顺序; 
                    // thread.IsBackground = true;//后台线程;进程关闭,线程也就消失了
                    //thread.IsBackground = false; //前台线程:进程关闭,线程执行完计算才消失
                }
                //{
    
    
                //    ParameterizedThreadStart mehtod = s =>
                //    {
    
    
                //        Console.WriteLine(s.ToString());
                //        this.DoSomethingLong("btnThread_Click");
                //    };
                //    Thread thread1 = new Thread(mehtod);
                //    thread1.Start("Hugh");
                //}

                //如果想要控制线程顺序呢?回调;其实是第一个线程里的动作执行完毕以后,去执行第二个动作呗;
                //1.其实是第一个线程里的动作执行完毕以后,去执行第二个动作呗;
                //2.既然是子线程来执行:必然是异步的,不能卡界面 ;
                //扩展封装一个; 
                //{
    
    
                //    ThreadStart method = () =>
                //    {
    
    
                //        Thread.Sleep(3000);
                //        Console.WriteLine("欢迎大家来到.Net高级班。。"); 
                //        Thread.Sleep(3000);
                //    };

                //    Action actionCallBack = () => {
    
    
                //        Console.WriteLine("大家来的挺齐;");
                //    };

                //    actionCallBack += () => {
    
    
                //        Console.WriteLine("这是多播委托的。。。");
                //    }; 
                //    this.ThreadWithCallBack(method, actionCallBack);
                //} 
                //那如果需要返回值呢?
                {
    
    
                    //2020
                    Func<int> func = () =>
                    {
    
    
                        Thread.Sleep(3000);
                        return DateTime.Now.Year;
                    };
                    //int iResult = this.ThreadWithReturen<int>(func);
                    //能得到2020这个结果吗? 
                    Func<int> func1Rusult = this.ThreadWithReturen<int>(func); //不卡界面 
                    {
    
    
                        Console.WriteLine("");
                        Console.WriteLine("这里的执行也需要3秒钟。。。");
                    }
                    int iRsult = func1Rusult.Invoke(); //这里会卡界面

                }
            }
            Console.WriteLine($"****************btnThread_Click End   {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
        }
        /// <summary>
        /// 控制线程顺序
        /// //两个委托封装回调
        /// </summary>
        /// <param name="threadStart"></param>
        /// <param name="actionCallBack"></param>
        private void ThreadWithCallBack(ThreadStart threadStart, Action actionCallBack)
        {
    
    
            //1.While 死循环 判断状态 等待
            //2.Join 
            //Thread thread = new Thread(threadStart);
            //thread.Start();
            {
    
    
                while (thread.ThreadState != ThreadState.Stopped)
                {
    
    
                    Thread.Sleep(100);
                }
                actionCallBack.Invoke();
            }
            //{
    
    
            //    thread.Join(); //卡界面
            //    actionCallBack.Invoke();
            //} 
            ThreadStart method = () =>
            {
    
    
                threadStart.Invoke();
                actionCallBack.Invoke();
            };

            Thread thread = new Thread(method);
            thread.Start();
        }

        /// <summary>
        /// 一个新的线程来执行委托里的动作
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="func"></param>
        /// <returns></returns>
        private Func<T> ThreadWithReturen<T>(Func<T> func)
        {
    
    
            #region MyRegion
            1.既需要异步执行,
            2.又需要有得到计算结果;
            根本做不到; 
            //T t = default(T);
            //ThreadStart threadStart = () =>
            //{
    
    
            //    t = func.Invoke();
            //};
            //Thread thread = new Thread(threadStart);
            //thread.Start();
            //thread.Join();//如果在这里Join,卡界面了呢?
            //return t; 
            1. 回调?
            2.Join、

            #endregion
            //花式玩法:
            //返回一个委托 
            T t = default(T);
            ThreadStart threadStart = () =>
            {
    
    
                t = func.Invoke();
            };
            Thread thread = new Thread(threadStart);
            thread.Start();//不卡界面

            return new Func<T>(() =>
            {
    
    
                thread.Join();
                return t;
            });
        }

2.ThreadPool


        /// <summary>
        /// 线程池
        /// 在.Netframwork2.0基于Thread做了个升级;
        /// Thread功能很强大,但是让开发者用不好;
        /// Thread:框架没有去控制线程数量;容易滥用,就疯狂开启线程数量,其实在开发中,业务处理不好,开线程就让   服务器扛不住;
        /// 就像给一个小孩儿一把热武器,不仅用不了,反而还会造成自身的伤害; 
        /// 池化思想:
        // 如果某个对象创建和销毁代价比较高,同时这个对象还可以反复使用的,就需要一个池子
        // 保存多个这样的对象,需要用的时候从池子里面获取;用完之后不用销毁,放回池子;(享元模式)  

        /// 如何去分配一个线程;
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnThreadpool_Click(object sender, EventArgs e)
        {
    
    
            Console.WriteLine($"****************btnThreadpool_Click Start   {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
            //1.如何分配一个线程;
            {
    
    
                //WaitCallback waitCallback = o =>
                //{
    
    
                //    Console.WriteLine(o);
                //    this.DoSomethingLong("btnThreadpool_Click");
                //};
                //ThreadPool.QueueUserWorkItem(waitCallback);
                //ThreadPool.QueueUserWorkItem(waitCallback,"欢迎大家"); 
            }
            {
    
    
                2.设置线程池中线程的数量
                //Console.WriteLine("*********************************************"); 
                //ThreadPool.SetMinThreads(2, 2); 
                //ThreadPool.SetMaxThreads(4, 4); //设置的最大值,不能小于计算机的逻辑线程数
                //ThreadPool.GetMinThreads(out int minworkerThreads, out int mincompletionPortThreads);
                //Console.WriteLine($"Min  this  minworkerThreads={minworkerThreads}    this mincompletionPortThreads={mincompletionPortThreads}"); 
                //ThreadPool.GetMaxThreads(out int maxworkerThreads, out int maxcompletionPortThreads);
                //Console.WriteLine($"Min  this  maxworkerThreads={maxworkerThreads}    this maxcompletionPortThreads={maxcompletionPortThreads}");
                线程池里的线程我们可以设置,但是不要随便折腾;因为设置以后,线程相当于当前进程而言,是全局的;
                Task Parallel都是来自于线程池; 但是new Thread 又可以新开一个线程;会占一个线程池的位置;
            }
            {
    
    
                3.线程等待; 观望式; 
                ManualResetEvent 默认要求参数状态false-----关闭-----mre.Set();--打开
                ManualResetEvent 状态参数true----打开---mre.Reset();-关闭
                //ManualResetEvent mre = new ManualResetEvent(false);
                //ThreadPool.QueueUserWorkItem(o =>
                //{
    
    
                //    Console.WriteLine(o);
                //    this.DoSomethingLong("欢迎大家来到.Net高级班的。。。。");
                //    mre.Set();//状态false----ture
                //    mre.Reset();
                //});
                //Console.WriteLine("do some thing else");
                //Console.WriteLine("do some thing else");
                //Console.WriteLine("do some thing else");
                //Console.WriteLine("do some thing else");
                //mre.WaitOne();//只要是mre状态编程true;就继续往后执行; 
                //Console.WriteLine("任务全部完成了。。。。。");
            }
            {
    
    
                    ThreadPool.SetMaxThreads(16, 16);
                    ManualResetEvent mre = new ManualResetEvent(false);
                    for (int i = 0; i < 18; i++)
                    {
    
    
                        int k = i;
                        ThreadPool.QueueUserWorkItem(t =>
                        {
    
    
                            Console.WriteLine($"ThreadId={Thread.CurrentThread.ManagedThreadId.ToString("00")} {k}");
                            if (k == 17)
                            {
    
    
                                mre.Set();
                            }
                            else
                            {
    
    
                                mre.WaitOne();
                            }
                        });
                    }
                    if (mre.WaitOne())   //只有在mre.Set();执行以后,状态值为true,才能往后执行;
                    {
    
    
                        Console.WriteLine("所有任务执行完成。。。。。。");
                    }
                }
            Console.WriteLine($"****************btnThreadpool_Click End   {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
        }

Guess you like

Origin blog.csdn.net/hello_mr_anan/article/details/108808999