C# Basics - Thread, ThreadPool, Task
2023-02-06 23:24:56  C#  >> Basics

Since .NET Framework 4.5, any method modified with async/await is considered an asynchronous method. In fact, these asynchronous methods are queue-based threaded tasks, and when you start using Task to run a piece of code, you actually start a thread, which by default is managed by the ThreadPool.

Thread

Thread, provided by the CLR, can provide fine-grained thread control, but it seems to be underpowered when it comes to return values, multiple threads in parallel/serial, and needs further encapsulation to work, and it requires time overhead to open and stop threads, which is wasteful if used indiscriminately.

ThreadPool

ThreadPool, provided by CLR, provides coarse-grained thread control and is mainly used to execute code fragments that are executed in a short period of time. A process has a thread pool, which is unified and scheduled by CLR. It has less control over threads and is also underpowered when returning values, multiple threads in parallel/serial.

Task

Task, a wrapper around ThreadPool and Thread, can choose whether to use a thread pool or a new thread depending on the duration of the task. And by further extending it, it adds features such as return values, multiple threads parallel/serial.

The core of Task is a scheduler, ThreadPoolTaskScheduler, by default. Task uses to operate a thread pool thread asynchronously.

A big difference between Task and Thread is that

  • If there is a block appears in Task, the whole Task will be blocked and the current thread ID will not change.
  • If there is a block in Thread, it will go to execute another thread and then come back to execute the original thread, and the thread ID will change to another ID.

ThreadPool is a pool of threads on basis of Thread to reduce the overhead of creating threads frequently. Threads are expensive, new stacks have to be opened and CPU context switching has to be added, so ThreadPool is suitable for small operations that are executed frequently and for short periods of time. The scheduling algorithm is adaptive and will adjust the configuration according to the pattern of program execution, so you usually do not need to schedule threads yourself. The IO thread corresponds to Native’s overlapped io, and the IO completion port is used under Win to achieve non-blocking IO.

Task or TPL is a higher level of encapsulation, the great thing is the continuation. The significance of continuation is that high-performance programs usually run on IO boundaries or UI event boundaries, and TPL’s continuation makes it easier to write such high-scalability code.

Task will decide whether to use Thread or ThreadPool based on some flags, such as whether it is long-running, and also do some detailed optimization, such as running several Task in the same thread, when continuation, Task will let the CPU idle for a few milliseconds to wait for the predecessor Task to finish to reduce CPU context switching.

Conclusion

  • Use Task as much as possible, and Thread or ThreadPool only secondarily.

  • While using a Task, tell the Task if it is long-running and try not to Wait.

  • Continuation after IO is best to end as soon as possible, and then release the thread, you can use the Worker to avoid affecting the later IO processes.


Good Day
😎