线程可以做什么是基于任务的异步模式 (TAP) 和任务并行 (TPL) with Task(或 Task<T>)不能做的?

What can Threads do that Task-based Asynchronous Pattern (TAP) and Task Parallelism (TPL) with Task (or Task<T>) cannot do?

在阅读 C# 中的多线程时(包括 MSDocs 和 Stephen Cleary 的 Concurrency in C# 等书籍),我反复遇到的建议基本上可以归结为:线程较旧,低 -级别,由 TaskTask<T> 类.

取代的并发抽象

现在我明白任务是更高级别的,功能更丰富和更强大,并且几乎可以做线程以前用于异步和并行的任何事情。

我的问题是:有什么线程可以做的,较新的 TaskTask<T> 等不能做的,所以我花时间学习多线程以防万一我遇到那些用例?

由于您提到的所有原因,任务都很不错,而且它们可以重用池中的线程。这避免了拥有大量线程的开销(每个线程都需要一个堆栈,以及内核中的一些控制结构,跟踪它们等等)并且还避免了任务切换的开销 - 内核在线程之间转换需要一些周期.如果您有很多线程竞争同一个 CPU,那么您将花更多的时间切换,而花更少的时间进行实际工作。

根据对您的问题的评论之一,直接使用线程意味着您可以控制生命周期,我唯一能想到的就是线程本地存储(https://docs.microsoft.com/en-us/dotnet/standard/threading/thread-local-storage-thread-relative-static-fields-and-data-slots)。

是的,你也需要了解线程。如果您对多线程一无所知,以下是您将无法执行的事情的非详尽列表:

  1. 当这些任务 运行 彼此并行时,您将无法同步这些任务的操作。由于对 locks、SemaphoreSlims、Mutexes、Barriers、Countdowns 等一无所知,您的并行和非同步任务将破坏应用程序的非线程安全状态。
  2. 您将无法使用 Interlocked class.
  3. 对您的任务使用的变量和字段进行原子突变
  4. 您将无法阻止编译器使用 reordering the instructions of your program, resulting to your tasks encountering invalid state, because you'll know nothing about memory barriers, the volatile 关键字和 Volatile class.
  5. 您将无法启动在 STA 线程上运行的 Task
  6. 您将无法启动在前台线程上运行的 Task
  7. 您将无法启动在 ThreadPriority 而非 Normal 的线程上运行的 Task
  8. 您将无法利用高效的对象池,其中每个线程都可以使用自己的专用对象 (ThreadLocal<T>)。

对于学习多线程,这里有一个免费的在线资源:Threading in C# Joseph Albahari。