← 全部文章 C# 语言

C# 多线程(三):Thread 和 Task 怎么选

2023 年 7 月 31 日 · 2 分钟读完

目录
  1. 五点差异
  2. 结论
  3. 延伸:上位机开发里的选型

前两篇分别讲了 Task 和 Thread 的用法,这一篇比较两者,看各自适合什么场景。

五点差异

Thread Task
创建和管理 显式创建一个系统线程,手动管理生命周期、优先级、状态 属于任务并行库(TPL),把「要做的事」和「在哪个线程做」解耦,默认交给线程池调度
异步编程 创建、启动、等待、结束、同步、通信都要手动处理,代码复杂容易出错 配合 async/await,写法接近同步代码,可读性好
返回值 ThreadStart 没有返回值,结果只能通过共享变量传出来 Task<T> 直接带回结果:int n = await CountAsync();
异常 线程里未处理的异常会直接让整个进程崩溃,外部捕获不到 异常保存在 Task 里,await 时在调用方的 try/catch 里抛出
线程复用 每次 new 都分配一个新的系统线程,频繁创建销毁开销大 使用线程池,线程反复复用

除此之外,Task 还自带取消(CancellationToken)、组合(WhenAll、WhenAny)、延续(ContinueWith)等能力,用 Thread 都要自己实现。

结论

Thread 是传统的多线程方式,什么都要自己管;Task 是现代 C# 推荐的方式,模型更简单、资源利用更好。新代码默认用 Task 和 async/await。

延伸:上位机开发里的选型

场景 推荐
点按钮后执行一个耗时操作,做完更新界面 async void 事件处理 + await Task.Run(...)
调用网络、文件、数据库 直接 await 它们的异步 API(HttpClient、ReadAsync)
同时处理多张图像、多个工位 多个 Task.Run + Task.WhenAll,或 Parallel.ForEach
软件运行期间一直轮询 PLC 或串口 一个后台 Thread,或 Task.Factory.StartNew(..., TaskCreationOptions.LongRunning)
需要设置线程优先级、STA 单元(如调用某些 COM 组件、剪贴板) Thread
定时执行 .NET 6 起的 PeriodicTimer:while (await timer.WaitForNextTickAsync(token)) { ... }

长期运行的循环不建议放进普通的 Task.Run:它会一直占着一个线程池线程,线程池线程不够时,其他任务要排队等新线程,可能出现莫名其妙的延迟。

# C# # 多线程 # Task

原文首发于 blog.csdn.net