ToB企服应用市场:ToB评测及商务社交产业平台

标题: 并发编程 ---为何要线程池化 [打印本页]

作者: 惊雷无声    时间: 2023-7-18 19:05
标题: 并发编程 ---为何要线程池化
引言

众所周知,使用线程可以极大的提高应用程序的效率和响应性,提高用户体验,但是不可以无节制的使用线程,为什么呢?
线程的开销

线程的开销实际上是非常大的,我们从空间开销和时间开销上分别讨论。
线程的空间开销

线程的空间开销来自这四个部分:
线程的时间开销

线程的时间开销来自这三个过程:
所以,由于要进行如此多的工作,所以创建和销毁一个线程就意味着代价“昂贵”,即使现在的CPU多核多线程,如无节制的使用线程,依旧会严重影响性能。
引入线程池

为了免程序员无节制地使用线程,微软开发了“线程池”技术。简单来说,线程池就是替开发人员管理工作线程。当一项工作完毕时,CLR不会销毁这个线程,而是会保留这个线程一段时间,看是否有别的工作需要这个线程。至于何时销毁或新起线程,由CLR根据自身的算法来做这个决定。
线程池技术能让我们重点关注业务的实现,而不是线程的性能测试。
微软除实现了线程池外,还需要关注一个类型:BackgroundWorker。 BackgroundWorker 是在内部使用了线程池的技术:同时,在WinForm或WPF编码中,它还给工作线程和UI线程提供了交互的能力。
实际上, Thread 和 ThreadPool 默认都没有提供这种交互能力,而 BackgroundWorker 却通过事件提供了这种能力。这种能力包括:报告进度、支持完成回调、取消任务、暂停任务等。
BackgroundWorker 的简单示例如下:
  1. private BackgroundWorker backgroundWorker = new BackgroundWorker();
  2. private void AsyncButton_Click(object sender, RoutedEventArgs e)
  3. {
  4.     //注册要执行的任务
  5.     backgroundWorker.DoWork += BackgroundWorker_DoWork;
  6.     //注册报告进度
  7.     backgroundWorker.ProgressChanged += BackgroundWorker_ProgressChanged;
  8.     //注册完成时的回调
  9.     backgroundWorker.RunWorkerCompleted += BackgroundWorker_RunWorkerCompleted;
  10.     //设置允许任务取消
  11.     backgroundWorker.WorkerSupportsCancellation = true;
  12.     //设置允许报告进度
  13.     backgroundWorker.WorkerReportsProgress = true;
  14.     backgroundWorker.RunWorkerAsync();
  15. }
  16. private void Cancel_Click(object sender, RoutedEventArgs e)
  17. {
  18.     //取消任务
  19.     if (backgroundWorker.IsBusy)
  20.         backgroundWorker.CancelAsync();
  21. }
  22. private void BackgroundWorker_RunWorkerCompleted(object? sender, RunWorkerCompletedEventArgs e)
  23. {
  24.     //完成时回调
  25.     MessageBox.Show("BackgroundWorker RunWorkerCompleted");
  26. }
  27. private void BackgroundWorker_ProgressChanged(object? sender, ProgressChangedEventArgs e)
  28. {   
  29.     //报告进度
  30.     this.textbox.Text = e.ProgressPercentage.ToString();
  31. }
  32. private void BackgroundWorker_DoWork(object? sender, DoWorkEventArgs e)
  33. {
  34.     BackgroundWorker? worker = sender as BackgroundWorker;
  35.     if (worker != null)
  36.     {
  37.         for (int i = 0; i < 20; i++)
  38.         {
  39.             if (worker.CancellationPending)
  40.             {
  41.                 e.Cancel = true;
  42.                 break;
  43.             }
  44.             worker.ReportProgress(i);
  45.             Thread.Sleep(100);
  46.         }
  47.     }
  48. }
复制代码
建议使用WinForm和WPF的开发人员使用 BackgroundWorker。
Task替代ThreadPool

ThreadPool 相对于 Thread 来说具有很多优势,但是 ThreadPool 在使用上却存在一定的不方便。比如:
所以随着 Task 类及其所提供的异步编程模型的引入,Task相较ThreadPool具有更多的优势。大概有一下几点:
所以,尽管ThreadPool在某些情况下仍然有其用途,但在C#编程中,使用Task替代ThreadPool已变为通用实践,推荐优先考虑使用Task来处理并发任务。
参考
编写高质量代码:改善C#程序的157个建议 / 陆敏技著.一北京:机械工业出版社,2011.9

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4