• C# 实现线程的常用几种方式


    前言

      在各个开发语言中,线程是避免不了的,或许通过表象看不出来,但是真的无处不在。就比如一个Web程序,平时或许只注重增删改查的开发,根本没有编写相关多线程的的代码,但是请求内部的时候,已经分配了对应线程进行处理了,以下简单说说C#中使用线程的几种方式,详细使用后续继续记录。

    Thread类实现

      Thread类的实现方式,在C# .NetFramework刚出的时候就已经存在了,起初刚开始的程序员都使用这种方式,但经历后面几个.NetFramework的版本更新,实现方式变的更多了。

    复制代码
         public void TestThread()
            {
                //这里需要注意的是:在C#中线程是离不开委托的
                //创建了一个线程对象,这里构造函数提供两类,一种不带参数的,一种是带参数的
                Thread thread = new Thread( TestAction);
                //设置线程相关属性
                thread.IsBackground = true;
                thread.Name = "Test";
                //启动线程
                thread.Start();
            }
    
            /// <summary>
            /// 线程执行的方法
            /// </summary>
            private void TestAction()
            {
                //这里实现线程处理的相关业务
                Console.WriteLine($"子线程Thread({Thread.CurrentThread.Name})执行相关业务操作....{Thread.CurrentThread.ManagedThreadId}");
            }
    复制代码

    运行结果:

     ThreadPool 线程池实现

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Threading;
     
    namespace MutltiThreadImplement
    {
        /// <summary>
        /// ThreadPool 池化线程,避免频繁的申请和释放消耗资源;之前Thread每次都要申请和释放。
        /// </summary>
        public class ThreadPoolImplement
        {
            public void TestThreadPool()
            {
                //可以设置相关属性
                ThreadPool.SetMinThreads(5,10);
                ThreadPool.SetMaxThreads(6, 10);
     
                //通过线程池自动分配线程执行对应的业务功能
                ThreadPool.QueueUserWorkItem(TestAction);
                 
                 
            }
     
            private void TestAction(object state)
            {
                //这里实现线程处理的相关业务
                Console.WriteLine($"子线程Thread({Thread.CurrentThread.Name})执行相关业务操作....{Thread.CurrentThread.ManagedThreadId}");
            }
        }
    }

      

      运行结果:

         ThreadPool的使用是不是感觉比较简单,但是就是因为太简单了,在业务中有些需求得不到满足,比如试着控制线程顺序;

    Delegate 实现的多线程

    复制代码
        public void TestDelegateThread()
            {
                //定义一个强类型委托, 可以自定义委托
                Action action = TestAction;
    
                //开始异步操作,其实内部是开启了子线程,看线程id不一样就明白了
                IAsyncResult asyncResult = action.BeginInvoke(CallBack, null);
    
                //可以根据返回对象的一些属性和方法进行判断和业务逻辑执行  具体可以查看相关文档
                //asyncResult.IsCompleted; //判读是否执行完成
                //asyncResult.AsyncWaitHandle.WaitOne(); //阻塞当前线程,直到收到信号量
            }
    
            private void TestAction()
            {
                //这里实现线程处理的相关业务
                Console.WriteLine($"子线程Thread({Thread.CurrentThread.Name})执行相关业务操作....{Thread.CurrentThread.ManagedThreadId}");
            }
    
            /// <summary>
            /// 子线程执行完成时的回调
            /// </summary>
            private void CallBack(IAsyncResult ar)
            {
                Console.WriteLine($"子线程{Thread.CurrentThread.ManagedThreadId}执行完毕");
            }    
    复制代码

    运行结果:

      

     注:  这种方式在.NetCore环境不支持,提示平台不支持。

    BackGroundWorker 实现

    复制代码
        BackgroundWorker backgroundWorker = new     BackgroundWorker();
    
            public void TestBackGroundWorker()
            {
                
                //这里使用的是事件的方式绑定业务处理方法
                backgroundWorker.DoWork += TestAction;
    
                //可以绑定一些事件    使用很简单,可以不需要绑定以下事件和设置属性就可以执行,根据需要进行绑定
                //执行完成事件
                backgroundWorker.RunWorkerCompleted += BackgroundWorker_RunWorkerCompleted;
                backgroundWorker.ProgressChanged += BackgroundWorker_ProgressChanged;
                backgroundWorker.WorkerReportsProgress = true;//只有执行这个属性之后才能进行ProgressChanged触发
    
    
                //开始执行操作
                backgroundWorker.RunWorkerAsync();
            }
    
            /// <summary>
            /// 触发事件之后的业务处理
            /// </summary>
            private void BackgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
            {
                Console.WriteLine("可以在这里更新UI线程上的东西....");
            }
    
            /// <summary>
            /// 触发事件之后的业务处理
            /// </summary>
            private void BackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
            {
                Console.WriteLine($"子线程{Thread.CurrentThread.ManagedThreadId}执行完成!!!");
            }
    
            private void TestAction(object sender, DoWorkEventArgs e)
            {
                //这里实现线程处理的相关业务
                Console.WriteLine($"子线程Thread({Thread.CurrentThread.Name})执行相关业务操作....{Thread.CurrentThread.ManagedThreadId}");
                //在业务方法中执行ReportProgress方法会触发ProgressChanged事件
                backgroundWorker.ReportProgress(10);
                Console.WriteLine($"子线程Thread({ Thread.CurrentThread.ManagedThreadId})执行相关业务操作结束");
            }    
    复制代码

    运行结果:

    BackgroundWorker 这种方式比较适应于窗体应用程序。

    Task 实现多线程

    复制代码
            /// <summary>
            /// Task 实现多线程, 目前为止,Task方式是大家都比较推荐的方式
            /// </summary>
            public void TestTask()
            {
                //创建一个Task实例
                Task task = new Task(TestAction);
                //开始任务
                task.Start();
            }
    
            private void TestAction()
            {
                //这里实现线程处理的相关业务
                Console.WriteLine($"子线程Thread({Thread.CurrentThread.Name})执行相关业务操作....{Thread.CurrentThread.ManagedThreadId}");
            }    
    复制代码

    运行结果

     Task实现多线程的方式是大家一致推荐的,俗称最佳实践。

    Parallel实现多线程

    复制代码
        /// <summary>
        /// Parallel 是对Task的进一步封装,但会阻塞主线程,主线程会参与业务逻辑处理
        /// </summary>
        public class ParallelImplement
        {
            public void TestParallel()
            {
                //分配线程执行业务逻辑,  Invoke可传多个业务处理,内部会自动分配线程处理
                Parallel.Invoke(TestAction);
            }
            private void TestAction()
            {
                //这里实现线程处理的相关业务
                Console.WriteLine($"子线程Thread({Thread.CurrentThread.Name})执行相关业务操作....{Thread.CurrentThread.ManagedThreadId}");
            }
        }
    复制代码

    运行结果:

     

     根据运行结果得出结论,主线程参与业务逻辑处理中,会阻塞线程, Parallel可根据业务进行选择使用。

    总结

      以上基本上就是C#中使用多线程常用的几种方式,这里只是简单的汇总方式,没有深入分析,后续将针对模块进行分析。

    JAVA&NET技术QQ群号:456257217有问题的可以在群里面提问。
  • 相关阅读:
    jquery ajax get 数组参数
    xcopy中文文件名,中文件目录乱码问题
    小程序使用wxParse插件解析html标签图片间距问题
    30分钟彻底弄懂flex布局
    abp ueditor 多图以及文件无法上传
    Lubuntu 18.04 自动登录
    树莓派虚拟环境手动安装HA
    ESP-01S刷ESPEasy固件,接入HA
    百度TTS的来由
    Pi 3B+编译安装python3.6.8
  • 原文地址:https://www.cnblogs.com/shiyh/p/14930586.html
Copyright © 2020-2023  润新知