前言
在各个开发语言中,线程是避免不了的,或许通过表象看不出来,但是真的无处不在。就比如一个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#中使用多线程常用的几种方式,这里只是简单的汇总方式,没有深入分析,后续将针对模块进行分析。