C#线程池
class Program { // 使用BeginXXX/EndXXX和IAsyncResult对象的方式被称为异步编程模型(APM模式) delegate string RunOnThreadPool(out int threadId); static void Main(string[] args) { int threadId = 0; // 给委托变量赋值 RunOnThreadPool poolDelegate = Test; var t = new Thread(() => { Test(out threadId); }); t.Start(); t.Join(); Console.WriteLine($"1.返回的线程Id:{threadId}"); // 通过调用委托变量的BeginInvoke方法来运行委托(执行Test方法) IAsyncResult ar = poolDelegate.BeginInvoke(out threadId, Callback, "异步委托调用"); ar.AsyncWaitHandle.WaitOne(); // 调用委托的EndInvoke会等待异步操作(Test方法)完成 // 异步操作执行完成之后,开始执行回掉函数;异步操作和回掉函数很可能会被线程池中同一个工作线程执行 string result = poolDelegate.EndInvoke(out threadId, ar); Console.WriteLine($"2.返回的线程Id:{threadId}"); Console.WriteLine($"返回值:{result}"); Console.ReadKey(); } static void Callback(IAsyncResult ar) { Console.WriteLine("开始执行回掉函数..."); Console.WriteLine($"异步状态:{ar.AsyncState}"); Console.WriteLine($"是否为线程池中的线程:{Thread.CurrentThread.IsThreadPoolThread}"); Console.WriteLine($"线程池工作线程Id:{Thread.CurrentThread.ManagedThreadId}"); } static string Test(out int threadId) { Console.WriteLine("开始测试方法..."); Console.WriteLine($"是否为线程池中的线程:{Thread.CurrentThread.IsThreadPoolThread}"); Thread.Sleep(TimeSpan.FromSeconds(2)); threadId = Thread.CurrentThread.ManagedThreadId; return $"线程Id:{threadId}"; } }
向线程池中放入异步操作
class Program { static void Main(string[] args) { ThreadPool.QueueUserWorkItem(AsyncOperation); Thread.Sleep(TimeSpan.FromSeconds(2)); ThreadPool.QueueUserWorkItem(AsyncOperation, "async state"); Thread.Sleep(TimeSpan.FromSeconds(2)); ThreadPool.QueueUserWorkItem(state => { Console.WriteLine($"操作状态:{state}"); Console.WriteLine($"工作线程Id:{Thread.CurrentThread.ManagedThreadId}"); Thread.Sleep(TimeSpan.FromSeconds(2)); }, "lambda state"); const int x = 1; const int y = 2; const string lambdaState = "lambda state 2"; // 使用闭包机制,无需传递lambda表达式的状态参数 ThreadPool.QueueUserWorkItem(_ => { Console.WriteLine($"操作状态:{x + y},{lambdaState}"); Console.WriteLine($"工作线程Id:{Thread.CurrentThread.ManagedThreadId}"); Thread.Sleep(TimeSpan.FromSeconds(2)); }); Console.ReadKey(); } static void AsyncOperation(object state) { Console.WriteLine($"操作状态:{state ?? "(null)"}"); Console.WriteLine($"工作线程Id:{Thread.CurrentThread.ManagedThreadId}"); Thread.Sleep(TimeSpan.FromSeconds(2)); } }
线程池与并行度:
static void Main(string[] args) { int threadCount = 500; var sw = new Stopwatch(); sw.Start(); UseThreads(threadCount); sw.Stop(); Console.WriteLine($"手动创建线程执行操作耗时:{sw.ElapsedMilliseconds}"); sw.Reset(); sw.Start(); UseThreadPool(threadCount); sw.Stop(); Console.WriteLine($"使用线程池执行操作耗时:{sw.ElapsedMilliseconds}"); Console.ReadKey(); } static void UseThreads(int threadCount) { using (CountdownEvent cdEvt = new CountdownEvent(threadCount)) { Console.WriteLine("开始创建线程"); for (int i = 0; i < threadCount; i++) { var thread = new Thread(() => { Console.WriteLine($"是否为线程池中的线程:{Thread.CurrentThread.IsThreadPoolThread},线程Id:{Thread.CurrentThread.ManagedThreadId}"); Thread.Sleep(TimeSpan.FromSeconds(0.1)); cdEvt.Signal(); }); thread.Start(); } cdEvt.Wait(); Console.WriteLine(); } } /// <summary> /// 线程池的用途是执行时间短的操作,使用线程池可以减少并行度消耗及节省操作系统资源 /// </summary> /// <param name="threadCount"></param> static void UseThreadPool(int threadCount) { using (CountdownEvent cdEvt = new CountdownEvent(threadCount)) { Console.WriteLine("开始使用线程池"); for (int i = 0; i < threadCount; i++) { ThreadPool.QueueUserWorkItem(_ => { Console.WriteLine($"是否为线程池中的线程:{Thread.CurrentThread.IsThreadPoolThread},线程Id:{Thread.CurrentThread.ManagedThreadId}"); Thread.Sleep(TimeSpan.FromSeconds(0.1)); cdEvt.Signal(); }); } cdEvt.Wait(); Console.WriteLine(); } } //在收到信号特定次数后取消阻止等待线程的同步基元 //可以使用取消令牌取消等待操作 //创建实例后,可以递增信号计数 //在 Reset 方法调用返回 Wait 后,可以重用实例 public void Test() { IEnumerable<Data> source = GetData(); using (CountdownEvent e = new CountdownEvent(1)) { foreach (Data element in source) { e.AddCount(); ThreadPool.QueueUserWorkItem(delegate (object state) { try { ProcessData(state); } finally { e.Signal(); } }, element); } } } static IEnumerable<Data> GetData() { return new List<Data>() { new Data(1), new Data(2), new Data(3), new Data(4), new Data(5) }; } static void ProcessData(object obj) { DataWithToken dataWithToken = (DataWithToken)obj; if (dataWithToken.Token.IsCancellationRequested) { Console.WriteLine("Canceled before starting {0}", dataWithToken.Data.Num); return; } for (int i = 0; i < 10000; i++) { if (dataWithToken.Token.IsCancellationRequested) { Console.WriteLine("Cancelling while executing {0}", dataWithToken.Data.Num); return; } Thread.SpinWait(100000); } Console.WriteLine("Processed {0}", dataWithToken.Data.Num); } static void EventWithCancel() { IEnumerable<Data> source = GetData(); CancellationTokenSource cts = new CancellationTokenSource(); Task.Factory.StartNew(() => { if (Console.ReadKey().KeyChar == 'c') cts.Cancel(); }); CountdownEvent e = new CountdownEvent(1); foreach (Data element in source) { DataWithToken item = new DataWithToken(element, cts.Token); e.AddCount(); ThreadPool.QueueUserWorkItem(delegate (object state) { ProcessData(state); if (!cts.Token.IsCancellationRequested) e.Signal(); }, item); } e.Signal(); try { e.Wait(cts.Token); } catch (OperationCanceledException oce) { if (oce.CancellationToken == cts.Token) { Console.WriteLine("User canceled."); } else { throw; //We don't know who canceled us! } } finally { e.Dispose(); cts.Dispose(); } } } class Data { public int Num { get; set; } public Data(int i) { Num = i; } public Data() { } } class DataWithToken { public CancellationToken Token { get; set; } public Data Data { get; private set; } public DataWithToken(Data data, CancellationToken ct) { this.Data = data; this.Token = ct; } }
取消异步操作:
static void Main(string[] args) { using (var cts = new CancellationTokenSource()) { CancellationToken token = cts.Token; ThreadPool.QueueUserWorkItem(_ => { AsyncOperation1(token); }); Thread.Sleep(TimeSpan.FromSeconds(2)); cts.Cancel(); } using (var cts = new CancellationTokenSource()) { CancellationToken token = cts.Token; ThreadPool.QueueUserWorkItem(_ => { AsyncOperation2(token); }); Thread.Sleep(TimeSpan.FromSeconds(2)); cts.Cancel(); } using (var cts = new CancellationTokenSource()) { CancellationToken token = cts.Token; ThreadPool.QueueUserWorkItem(_ => { AsyncOperation3(token); }); Thread.Sleep(TimeSpan.FromSeconds(2)); cts.Cancel(); } Console.ReadKey(); } static void AsyncOperation1(CancellationToken token) { Console.WriteLine("启动第一个异步操作"); for (int i = 0; i < 5; i++) { // 轮询检查IsCancellationRequested属性 if (token.IsCancellationRequested) { Console.WriteLine("第一个异步操作被取消啦~~~"); return; } Thread.Sleep(TimeSpan.FromSeconds(1)); } Console.WriteLine("第一个异步操作完成"); } static void AsyncOperation2(CancellationToken token) { try { Console.WriteLine("启动第二个异步操作"); for (int i = 0; i < 5; i++) { // 抛出异常,取消操作时,通过操作之外的代码来处理 token.ThrowIfCancellationRequested(); Thread.Sleep(TimeSpan.FromSeconds(1)); } Console.WriteLine("第二个异步操作完成"); } catch (OperationCanceledException ex) { Console.WriteLine($"第二个异步操作被取消,异常消息:{ex.Message}"); } } static void AsyncOperation3(CancellationToken token) { bool cancellationFlag = false; // 注册回调函数,当操作被取消时,线程池将调用该回调函数 token.Register(() => { cancellationFlag = true; }); Console.WriteLine("启动第三个异步操作"); for (int i = 0; i < 5; i++) { if (cancellationFlag) { Console.WriteLine("第三个异步操作被取消啦~~~"); return; } Thread.Sleep(TimeSpan.FromSeconds(1)); } Console.WriteLine("第三个异步操作完成"); }
在线程池中使用等待事件处理器及超时
static void Main(string[] args) { RunOperation(TimeSpan.FromSeconds(5)); RunOperation(TimeSpan.FromSeconds(7)); Console.ReadKey(); } static void RunOperation(TimeSpan workerOperationTs) { using (var evt = new ManualResetEvent(false)) using (var cts = new CancellationTokenSource()) { Console.WriteLine("注册操作超时的方法..."); var worker = ThreadPool.RegisterWaitForSingleObject(evt, (state, isTimeout) => WorkerOperationWait(cts, isTimeout), null, workerOperationTs, true); Console.WriteLine("开始长时间操作..."); ThreadPool.QueueUserWorkItem(_ => { WorkerOperation(cts.Token, evt); }); Thread.Sleep(workerOperationTs.Add(TimeSpan.FromSeconds(2))); worker.Unregister(evt); } } static void WorkerOperation(CancellationToken token, ManualResetEvent evt) { for (int i = 0; i < 6; i++) { if(token.IsCancellationRequested) { Console.WriteLine("异步操作被取消"); return; } Thread.Sleep(TimeSpan.FromSeconds(1)); } evt.Set(); } static void WorkerOperationWait(CancellationTokenSource cts,bool isTimeout) { if(isTimeout) { cts.Cancel(); Console.WriteLine("异步操作超时并被取消了"); } else { Console.WriteLine("异步操作完成"); } }