线程学习--Threads

  • 线程

        #region Threads

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

            //Action action = () => this.DoSomethingLong("btnThreads_Click");
            ThreadStart threadStart = () => this.DoSomethingLong("btnThreads_Click");

            Thread thread = new Thread(threadStart);
            thread.Start();

            //thread.Suspend(); // 线程挂起 (不推荐,抛弃)
            //thread.Resume();  // 唤醒线程 (不推荐,抛弃)
            //thread.Abort();   // 销毁,方式是抛异常 (也不建议使用) 不一定及时、有些动作发出收不回来
            //Thread.ResetAbort(); // 取消异常

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

        }

        #endregion
  • 线程等待
            thread.Join(); // 当前线程等待Thread完成
            thread.Join(500); // 最多等待500ms

            while(thread.ThreadState != ThreadState.Stopped)
            {
                Thread.Sleep(100); // 当前线程休息100ms
            }
  • 前后台线程
            Console.WriteLine(thread.IsBackground); 
            // 默认是前台线程,启动之后一定要完成任务的,阻止进程退出
            thread.IsBackground = true; // 指定后台线程:随着进程退出
  • 线程优先级
            thread.Priority = ThreadPriority.Highest;
            // CPU会优先执行,但不代表说Highest就最先完成
  • ThreadPool线程池

  • ThreadPool用法

        #region ThreadPool

        /// <summary>
        /// 2.0   享元模式  数据库连接池 
        /// 1.thread提供了太多API
        /// 2.无限使用线程,加以限制
        /// 3.重用线程,避免重复的创建和销毁
        /// </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")}***************");

            ThreadPool.QueueUserWorkItem(t => this.DoSomethingLong("btnThreadPool_Click"));

            ThreadPool.SetMaxThreads(16, 16);
            ThreadPool.SetMinThreads(8, 8);

            {
                ThreadPool.GetMaxThreads(out int workerThreads, out int completionPortThreads);
                //辅助线程的最大数目  异步线程的最大数目
                Console.WriteLine($"workerThreads={workerThreads}
                    completionPortThreads={completionPortThreads}");

            }
            {
                ThreadPool.GetMinThreads(out int workerThreads, out int completionPortThreads);
            }

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

        #endregion
  • ThreadPool线程等待
           // ThreadPool啥都没有 如何等待?
            ManualResetEvent manualResetEvent = new ManualResetEvent(false);
            // false  WaitOne等待 Set  true
            // true   WaitOne直接过去 reset false WaitOne等待

            ThreadPool.QueueUserWorkItem(t =>
            {
                this.DoSomethingLong("btnThreadPool_Click");
                manualResetEvent.Set(); // 置成true
                // manualResetEvent.Reset(); // 置成false
            });
            manualResetEvent.WaitOne();

也有缺点,一般来说,不要阻塞线程池的线程

        // 启动子线程计算 -- 完成委托后,该线程去执行后续回调委托
        private void ThreadWithCallback(Action act, Action callback)
        {
            Thread thread = new Thread(() => {
                act.Invoke();
                callback.Invoke();
            });
            thread.Start();
        }
         this.ThreadWithCallback(() => 
            Console.WriteLine($"这里是action 
            {Thread.CurrentThread.ManagedThreadId.ToString("00")}")
            , () => 
            Console.WriteLine($"这里是callback 
            {Thread.CurrentThread.ManagedThreadId.ToString("00")}"));
        // 带返回的异步调用 需要获取返回值
        private Func<T> ThreadWithReturn<T> (Func<T> func)
        {
            T t = default(T);
            Thread thread = new Thread(()=>
            {
                t = func.Invoke();
            });
            thread.Start();

            return () =>
            {
                //while (thread.ThreadState != ThreadState.Stopped)
                //{
                //    Thread.Sleep(200);
                //}
                thread.Join();
                return t;
            };

        }
            Func<int> func = this.ThreadWithReturn<int>(() =>
            {
                Thread.Sleep(2000);
                return DateTime.Now.Millisecond;
            });
            Console.WriteLine("12324546576586789789");

            int iResult = func.Invoke();
            Console.WriteLine(iResult);
  • Task

        #region Task
        /// <summary>
        /// 3.0 Task 是基于ThreadPool
        /// </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.ToString("00")} " +
                         $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");

            Task.Run(() => this.DoSomethingLong("btnTask_Click1"));
            Task.Run(() => this.DoSomethingLong("btnTask_Click2"));

            TaskFactory taskFactory = Task.Factory;// 4.0
            taskFactory.StartNew(() => this.DoSomethingLong("btnTask_Click3"));

            new Task(() => this.DoSomethingLong("btnTask_Click4")).Start();

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

        #endregion
  • 什么时候用多线程?

任务能并发进行:提升速度 优化体验

           List<Task> taskList = new List<Task>();
           Console.WriteLine($"项目经理启动一个项目。。。【{Thread.CurrentThread.ManagedThreadId.ToString("00")}】");
           Console.WriteLine($"前置准备工作。。。【{Thread.CurrentThread.ManagedThreadId.ToString("00")}】");
           Console.WriteLine($"开始编程。。。【{Thread.CurrentThread.ManagedThreadId.ToString("00")}】");

           taskList.Add(Task.Run(() => this.Coding("小张", "Client")));
           taskList.Add(Task.Run(() => this.Coding("小王", "Portal")));
           taskList.Add(Task.Run(() => this.Coding("小李", "Service")));
           taskList.Add(Task.Run(() => this.Coding("小陈", "Jump")));
           taskList.Add(Task.Run(() => this.Coding("小爱", "Monitor")));

           // 一个业务查询操作有多个数据源,首页-多线程并发-拿到全部数据后才能返回 WaitAll
           // 一个商品搜索操作有多个数据源,商品搜索- 多个数据源- 多线程并发-只需要一个结果即可 WaitAny
           // 阻塞:需要完成后再继续
           Task.WaitAny(taskList.ToArray()); // 会阻塞当前线程,等着某个任务完成后,才进入下一行
           Console.WriteLine($"完成里程碑【{Thread.CurrentThread.ManagedThreadId.ToString("00")}】");

           // 多线程加快速度,但全部任务完成后,才能执行的操作
           Task.WaitAll(taskList.ToArray());// 会阻塞当前线程,等着全部任务都完成后,才进入下一行

           Task.WaitAll(taskList.ToArray(), 1000);
           Console.WriteLine("等待1s后,执行动作");

           Console.WriteLine($"甲方验收。。。【{Thread.CurrentThread.ManagedThreadId.ToString("00")}】");
        /// <summary>
        /// 编码做项目
        /// </summary>
        /// <param name="name"></param>
        /// <param name="project"></param>
        private void Coding(string name, string project)
        {
            Console.WriteLine($"****************Coding {name} Start {project} {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
            long lResult = 0;
            for (int i = 0; i < 1000000000; i++)
            {
                lResult += i;
            }
            //Thread.Sleep(2000);

            Console.WriteLine($"****************Coding {name}   End {project} {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")} {lResult}***************");
        }

以上都会阻塞线程,下面的不阻塞:

            TaskFactory taskFactory = new TaskFactory();
            taskFactory.ContinueWhenAll(taskList.ToArray(), tList =>
            {
                Console.WriteLine($"部署环境,联调测试。。。【{Thread.CurrentThread.ManagedThreadId.ToString("00")}】");
            });
            taskFactory.ContinueWhenAny(taskList.ToArray(), t =>
            {
                Console.WriteLine($"部署环境,联调测试。。。【{Thread.CurrentThread.ManagedThreadId.ToString("00")}】");
            });

            Task.WhenAny(taskList.ToArray()).ContinueWith(t =>
            {
                Console.WriteLine($"得意的笑。。。【{Thread.CurrentThread.ManagedThreadId.ToString("00")}】");
            });
            Task.WhenAll(taskList.ToArray()).ContinueWith(t =>
            {
                Console.WriteLine($"部署环境,联调测试。。。【{Thread.CurrentThread.ManagedThreadId.ToString("00")}】");
            });
  • 完成10000个任务 但是只要10个线程
                List<int> list = new List<int>();
                for (int i = 0; i < 10000; i++)
                {
                    list.Add(i);
                }
                // 完成10000个任务 但是只要10个线程
                Action<int> action = i =>
                {
                    Console.WriteLine(Thread.CurrentThread.ManagedThreadId.ToString("00"));
                    Thread.Sleep(new Random(i).Next(100, 300));
                };
                List<Task> taskList = new List<Task>();
                foreach (var item in list)
                {
                    int k = item;
                    Task.Run(() => action.Invoke(k));
                    if (taskList.Count > 10)
                    {
                        Task.WaitAny(taskList.ToArray());
                        taskList.Where(t => t.Status != TaskStatus.RanToCompletion).ToList();
                    }
                }
                Task.WhenAll(taskList.ToArray());

想知道线程是由哪个完成的

            TaskFactory taskFactory = new TaskFactory();
            List<Task> taskList = new List<Task>();
            taskList.Add(taskFactory.StartNew(o => this.Coding("爱书客", "Client"), "爱书客"));
            taskList.Add(taskFactory.StartNew(o => this.Coding("风动寂野", "Portal"), "风动寂野"));
            taskList.Add(taskFactory.StartNew(o => this.Coding("笑看风云", "Service"), "笑看风云"));
            taskFactory.ContinueWhenAny(taskList.ToArray(), t =>
            {
                Console.WriteLine(t.AsyncState);
                Console.WriteLine($"部署环境,联调测试。。。【{Thread.CurrentThread.ManagedThreadId.ToString("00")}】");
            });
            taskFactory.ContinueWhenAll(taskList.ToArray(), tList =>
            {
                Console.WriteLine(tList[0].AsyncState);
                Console.WriteLine($"部署环境,联调测试。。。【{Thread.CurrentThread.ManagedThreadId.ToString("00")}】");
            });
            Task.Run(
                    () =>
                    {
                        Task.WaitAny(taskList.ToArray());//会阻塞当前线程,等着某个任务完成后,才进入下一行  卡界面
                                                         //Task.WaitAny(taskList.ToArray(), 1000);
                        Console.WriteLine($"完成里程碑 【{Thread.CurrentThread.ManagedThreadId.ToString("00")}】");

                        //多线程加快速度,但是全部任务完成后,才能执行的操作
                        Task.WaitAll(taskList.ToArray());//会阻塞当前线程,等着全部任务完成后,才进入下一行  卡界面
                        Console.WriteLine($"告诉甲方验收,上线使用【{Thread.CurrentThread.ManagedThreadId.ToString("00")}】");
                    });
  • 延迟
            {
                Task.Delay(1000);//延迟  不会卡
                Thread.Sleep(1000);//等待   卡

                Stopwatch stopwatch = new Stopwatch();
                stopwatch.Start();
                Thread.Sleep(2000);
                stopwatch.Stop();
                Console.WriteLine(stopwatch.ElapsedMilliseconds);
            }
            {
                Stopwatch stopwatch = new Stopwatch();
                stopwatch.Start();
                Task.Delay(2000).ContinueWith(t =>
                {
                    stopwatch.Stop();
                    Console.WriteLine(stopwatch.ElapsedMilliseconds);
                });
            }
            {
                Stopwatch stopwatch = new Stopwatch();
                stopwatch.Start();
                Task.Run(() =>
                {
                    Thread.Sleep(2000);
                    stopwatch.Stop();
                    Console.WriteLine(stopwatch.ElapsedMilliseconds);
                });
            }
  • 并行编程

        #region Parallel
        /// <summary>
        /// 并行编程  在Task的基础上做了封装 4.5
        /// Parallel 卡界面,调用parallel线程参与计算,节约了一个线程
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnParallel_Click(object sender, EventArgs e)
        {
            Console.WriteLine($"****************btnParallel_Click Start " +
                $"{Thread.CurrentThread.ManagedThreadId.ToString("00")} " +
                $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");

            //Parallel.Invoke(() => this.Coding("爱书客", "Client")
            //    , () => this.Coding("风动寂野", "Portal")
            //    , () => this.Coding("笑看风云", "Service"));

            //Parallel.For(0, 5, i => this.Coding("爱书客", "Client" + i));
            //Parallel.ForEach(new string[] { "0","1","2","3","4"}, i => this.Coding("爱书客", "Client" + i));

            Console.WriteLine($"****************btnParallel_Click End   " +
                $"{Thread.CurrentThread.ManagedThreadId.ToString("00")} " +
                $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
        }
        #endregion

parallelOptions 可以控制并发数量:

            ParallelOptions parallelOptions = new ParallelOptions();
            parallelOptions.MaxDegreeOfParallelism = 3;
            Parallel.For(0, 10, parallelOptions, i => this.Coding("爱书客", "Client" + i));
            Task.Run(() =>
            {
                ParallelOptions parallelOptions = new ParallelOptions();
                parallelOptions.MaxDegreeOfParallelism = 3;
                Parallel.For(0, 10, parallelOptions, i => this.Coding("爱书客", "Client" + i));
            });
posted @ 2020-05-13 23:13  一纸年华  阅读(8)  评论(0编辑  收藏  举报  来源