1、Thread的使用
Thread
是C#语言对线程对象的封装 ,从.NET 1.0版本就开始存在。
1)Thread初始化
using System; using System.Threading; namespace ConsoleApplication { class Program { private static void TaskFunc(string name) { //获取正在运行的线程 Thread thread = Thread.CurrentThread; //设置线程的名字 thread.Name = name; //获取当前线程的唯一标识符 int id = thread.ManagedThreadId; //获取当前线程的状态 System.Threading.ThreadState state = thread.ThreadState; //获取当前线程的优先级 ThreadPriority priority = thread.Priority; string strMsg = string.Format("Thread ID:{0}\n" + "Thread Name:{1}\n" + "Thread State:{2}\n" + "Thread Priority:{3}\n", id, thread.Name, state, priority); Console.WriteLine(strMsg); } static void Main(string[] args) { Action action = () => TaskFunc("action"); ThreadStart threadStart = () => TaskFunc("线程2"); //Thread thread = new Thread(action);//不可以这样初始化 Thread thread = new Thread(() => TaskFunc("线程1")); thread.Start(); Thread thread2 = new Thread(threadStart); thread2.Start(); Console.ReadKey(); } } }
2)Thread的常用操作
using System; using System.Threading; namespace ConsoleApplication { class Program { static bool isRun = false; private static void TaskFunc(string name) { //获取正在运行的线程 Thread thread = Thread.CurrentThread; //设置线程的名字 thread.Name = name; //获取当前线程的唯一标识符 int id = thread.ManagedThreadId; //获取当前线程的状态 System.Threading.ThreadState state = thread.ThreadState; //获取当前线程的优先级 ThreadPriority priority = thread.Priority; string strMsg = string.Format("Thread ID:{0}\n" + "Thread Name:{1}\n" + "Thread State:{2}\n" + "Thread Priority:{3}\n", id, thread.Name, state, priority); Console.WriteLine(strMsg); while (isRun) { Thread.Sleep(500); } } static void Main(string[] args) { isRun = true; Thread thread = new Thread(() => TaskFunc("线程1")); //1、线程启动 thread.Start(); //thread.Suspend();//线程挂起_已弃用 //thread.Resume();//唤醒线程_已弃用 //2、线程销毁 try { //thread.Abort();//销毁,方式是抛异常 不推荐使用 } catch (Exception) { //Thread.ResetAbort();//取消Abort异常 } //3、线程等待 thread.Join(500);//最多等500 Console.WriteLine("等待500ms"); isRun = false; thread.Join();//当前线程等待thread完成 //4、判断线程是否停止 //while (thread.ThreadState != ThreadState.Stopped) //{ // Thread.Sleep(100);//当前线程 休息100ms //} //5、设置后台线程 //默认是前台线程,启动之后一定要完成任务的,阻止进程退出 //thread.IsBackground = true;//指定后台线程:进程退出则退出 //6、设置线程优先级 //thread.Priority = ThreadPriority.Highest;//线程优先级 //CPU会优先执行 Highest 不代表说Highest就最先 Console.ReadKey(); } } }
3)前台线程与后台线程的区别
Thread默认是前台线程,启动之后一定要完成任务的,阻止进程退出,就是一定要线程运行完毕进程才会退出。而后台线程是进程的退出线程也退出。
4)Thread实现回调
using System; using System.Threading; namespace ConsoleApplication { class Program { private static void TaskFunc(string name) { //获取正在运行的线程 Thread thread = Thread.CurrentThread; //设置线程的名字 thread.Name = name; //获取当前线程的唯一标识符 int id = thread.ManagedThreadId; //获取当前线程的状态 System.Threading.ThreadState state = thread.ThreadState; //获取当前线程的优先级 ThreadPriority priority = thread.Priority; string strMsg = string.Format("Thread ID:{0}\n" + "Thread Name:{1}\n" + "Thread State:{2}\n" + "Thread Priority:{3}\n", id, thread.Name, state, priority); Console.WriteLine(strMsg); } //启动子线程计算--完成委托后,该线程去执行后续回调委托 private static void ThreadWithCallback(Action act, Action callback) { Thread thread = new Thread(() => { act.Invoke(); callback.Invoke(); }); thread.Start(); } /// /// 又要结果 要不阻塞 /// /// /// /// private static Func<T> ThreadWithReturn<T>(Func<T> func) { T t = default(T); Thread thread = new Thread(() => { t = func.Invoke(); }); thread.Start(); return () => { thread.Join(); return t; }; } static void Main(string[] args) { Thread thread = new Thread(() => TaskFunc("线程1")); //不带返回值回调 ThreadWithCallback(() => Console.WriteLine($"主线程执行 {Thread.CurrentThread.ManagedThreadId.ToString("00")}") , () => Console.WriteLine($"回调执行 {Thread.CurrentThread.ManagedThreadId.ToString("00")}")); //带返回值回调 Func<DateTime> func = ThreadWithReturn(() => { Thread.Sleep(1000); return DateTime.Now; }); Console.WriteLine("返回值:" + func.Invoke()); Console.ReadKey(); } } }
2、Task的使用
Task
是.NET4.0加入的,与线程池ThreadPool
的功能类似,用Task
开启新任务时,会从线程池中调用线程,而Thread
每次实例化都会创建一个新的线程。我们可以说
Task
是一种基于任务的编程模型。它与Thread
的主要区别是,更加方便对线程进程调度和获取线程的执行结果。并且
Task
是针对多核有优化。
1)Task启动的方式
using System; using System.Threading; using System.Threading.Tasks; namespace ConsoleApplication { class Program { private static void TaskFunc(string name) { //获取正在运行的线程 Thread thread = Thread.CurrentThread; //设置线程的名字 //thread.Name = name;//只能设置一次 Console.WriteLine(thread.Name); Console.WriteLine(name); //获取当前线程的唯一标识符 int id = thread.ManagedThreadId; //获取当前线程的状态 System.Threading.ThreadState state = thread.ThreadState; //获取当前线程的优先级 ThreadPriority priority = thread.Priority; string strMsg = string.Format("Thread ID:{0}\n" + "Thread Name:{1}\n" + "Thread State:{2}\n" + "Thread Priority:{3}\n", id, thread.Name, state, priority); Console.WriteLine(strMsg); //执行耗时间耗资源的任务 Console.WriteLine(DateTime.Now.Ticks); } static void Main(string[] args) { //三种Task启动的方式 var t1 = Task.Run(() => TaskFunc("线程1")); var t2 = Task.Factory.StartNew(() => TaskFunc("线程2")); var t3 = new Task(() => TaskFunc("线程3")); t3.Start(); //启动带回调 var t4 = Task.Run(() => TaskFunc("线程4")).ContinueWith(t => { Console.WriteLine(t.AsyncState); }); Task.WaitAll(t1, t2, t3, t4); Console.ReadKey(); } } }
2) Thread.Sleep()和Task.Delay()的使用
using System; using System.Diagnostics; using System.Threading; using System.Threading.Tasks; namespace ConsoleApplication { class Program { private static void TaskFunc(string name="") { //获取正在运行的线程 Thread thread = Thread.CurrentThread; //设置线程的名字 //thread.Name = name;//只能设置一次 Console.WriteLine(thread.Name); Console.WriteLine(name); //获取当前线程的唯一标识符 int id = thread.ManagedThreadId; //获取当前线程的状态 System.Threading.ThreadState state = thread.ThreadState; //获取当前线程的优先级 ThreadPriority priority = thread.Priority; string strMsg = string.Format("Thread ID:{0}\n" + "Thread Name:{1}\n" + "Thread State:{2}\n" + "Thread Priority:{3}\n", id, thread.Name, state, priority); Console.WriteLine(strMsg); //执行耗时间耗资源的任务 Console.WriteLine(DateTime.Now.Ticks); } static void Main(string[] args) { //同步延时,阻塞主线程 Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); Thread.Sleep(500); stopwatch.Stop(); Console.WriteLine("stopwatch:" + stopwatch.ElapsedMilliseconds); TaskFunc(); //异步延时,不阻塞主线程 Stopwatch stopwatch2 = new Stopwatch(); stopwatch2.Start(); var t1= Task.Delay(500).ContinueWith(t => { stopwatch2.Stop(); Console.WriteLine("stopwatch2:" + stopwatch2.ElapsedMilliseconds); }); TaskFunc(); //同步+异步延时,不阻塞主线程 Stopwatch stopwatch3 = new Stopwatch(); stopwatch3.Start(); var t2=Task.Run(() => { Thread.Sleep(500); stopwatch3.Stop(); Console.WriteLine("stopwatch3:" + stopwatch3.ElapsedMilliseconds); TaskFunc(); }); Task.WaitAll(t1, t2); } } }
3)通过判断线程状态来控制线程最大运行数
using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Threading; using System.Threading.Tasks; namespace ConsoleApplication { class Program { private static void TaskFunc(string name = "") { //获取正在运行的线程 Thread thread = Thread.CurrentThread; //设置线程的名字 //thread.Name = name;//只能设置一次 Console.WriteLine(thread.Name); Console.WriteLine(name); //获取当前线程的唯一标识符 int id = thread.ManagedThreadId; //获取当前线程的状态 System.Threading.ThreadState state = thread.ThreadState; //获取当前线程的优先级 ThreadPriority priority = thread.Priority; string strMsg = string.Format("Thread ID:{0}\n" + "Thread Name:{1}\n" + "Thread State:{2}\n" + "Thread Priority:{3}\n", id, thread.Name, state, priority); Console.WriteLine(strMsg); //执行耗时间耗资源的任务 Console.WriteLine(DateTime.Now.Ticks); } static void Main(string[] args) { var maxCount = 2; List<int> list = new List<int>(); for (int i = 0; i < 100; i++) { list.Add(i); } Action<int> action = i => { TaskFunc(); Thread.Sleep(10); }; List<Task> taskList = new List<Task>(); foreach (var i in list) { int k = i; taskList.Add(Task.Run(() => action.Invoke(k))); if (taskList.Count > maxCount) { Task.WaitAny(taskList.ToArray()); taskList = taskList.Where(t => t.Status != TaskStatus.RanToCompletion).ToList(); Console.WriteLine("运行中的任务数:" + taskList.Count); } } //异步等待其全部执行完毕,不阻塞线程 Task wTask = Task.WhenAll(taskList.ToArray()); //wTask.ContinueWith()... //死等线程全部执行完毕,阻塞后面的线程 Task.WaitAll(taskList.ToArray()); //Task.WaitAll()和Task.WhenAll()区别一个阻塞线程,一个不阻塞 } } }
3、Parallel的使用
Parallel
是并行编程,在Task的基础上做了封装,.NET FrameWork 4.5之后的版本可用,调用Parallel
线程参与执行任务。
1)Parallel.For()和Parallel.ForEach()的使用
using System; using System.Threading; using System.Threading.Tasks; namespace ConsoleApplication { class Program { private static void TaskFunc(string name = "") { //获取正在运行的线程 Thread thread = Thread.CurrentThread; //设置线程的名字 //thread.Name = name;//只能设置一次 Console.WriteLine(thread.Name); Console.WriteLine(name); //获取当前线程的唯一标识符 int id = thread.ManagedThreadId; //获取当前线程的状态 System.Threading.ThreadState state = thread.ThreadState; //获取当前线程的优先级 ThreadPriority priority = thread.Priority; string strMsg = string.Format("Thread ID:{0}\n" + "Thread Name:{1}\n" + "Thread State:{2}\n" + "Thread Priority:{3}\n", id, thread.Name, state, priority); Console.WriteLine(strMsg); //执行耗时间耗资源的任务 Console.WriteLine(DateTime.Now.Ticks); } static void Main(string[] args) { Parallel.For(0, 5, i => { Console.WriteLine("i="+i); TaskFunc(); }); Parallel.ForEach(new string[] { "0", "1", "2", "3", "4" }, j => { Console.WriteLine("j="+j); TaskFunc(); }); } } }
2)ParallelOptions 控制并发数量
using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Threading; using System.Threading.Tasks; namespace ConsoleApplication { class Program { private static void TaskFunc(string name = "") { //获取正在运行的线程 Thread thread = Thread.CurrentThread; //设置线程的名字 //thread.Name = name;//只能设置一次 Console.WriteLine(thread.Name); Console.WriteLine(name); //获取当前线程的唯一标识符 int id = thread.ManagedThreadId; //获取当前线程的状态 System.Threading.ThreadState state = thread.ThreadState; //获取当前线程的优先级 ThreadPriority priority = thread.Priority; string strMsg = string.Format("Thread ID:{0}\n" + "Thread Name:{1}\n" + "Thread State:{2}\n" + "Thread Priority:{3}\n", id, thread.Name, state, priority); Console.WriteLine(strMsg); //执行耗时间耗资源的任务 Console.WriteLine(DateTime.Now.Ticks); } static void Main(string[] args) { //state.Break()和state.Stop() 都不推荐用,异常情况处理较麻烦 ParallelOptions parallelOptions = new ParallelOptions(); parallelOptions.MaxDegreeOfParallelism = 2;//控制并发数量 Parallel.For(1, 12, parallelOptions, (i, state) => { //state.Stop();/* //调用 Stop 方法指示尚未开始的循环的任何迭代都无需运行。 它可以有效地取消循环的任何其他迭代。 但是,它不会停止已经开始执行的任何迭代。 //调用 Stop 方法会导致此 IsStopped 属性返回到 true 仍在执行的循环的任何迭代。 这对于长时间运行的迭代特别有用,它可以检查 IsStopped 属性并在其值为时提前退出 true 。 //Stop 通常在基于搜索的算法中使用,在找到结果后,不需要执行其他迭代。 //state.Break(); //Break 指示应运行当前迭代之后的任何迭代。 它可以有效地取消循环的任何其他迭代。 但是,它不会停止已经开始执行的任何迭代。 例如,如果 Break 是从从0到1000的并行循环的第100迭代调用的,则所有小于100的迭代仍应运行,但不会执行从101到1000的迭代。 //对于可能已在执行的长时间运行的迭代, Break LowestBreakIteration 如果当前索引小于的当前值,则将属性设置为当前迭代的索引 LowestBreakIteration 。 若要停止其索引大于从争用执行的最低中断迭代的迭代,应执行以下操作: //检查属性是否 ShouldExitCurrentIteration 为 true 。 //如果其索引大于属性值,则从迭代退出 LowestBreakIteration 。 //说明如示例所示。 //Break 通常在基于搜索的算法中采用,其中排序在数据源中存在。 TaskFunc(); }); } } }
相关文档:C# 多线程(Thread和Task)