线程、任务、async和await,它们实际上是如何工作的?

huangapple go评论78阅读模式
英文:

Threads, Tasks, async and await, how do they actually work?

问题

I'm currently learning about C#, I'm wondering how Thread, Task, async, and await really work. This is what I understand:

  • Task.Run(MyTask) is always executed on a new thread (in the thread pool).
  • Because of this, Task will run in parallel with the method that calls it (because they are on two different threads).
  • Therefore, use await to wait for the result of that Task, then continue executing the code below.
  • This is my example code:
static void Main(string[] args)
{
    Task.Run(MyTask);
    Console.WriteLine("Do main work...");
    Thread.Sleep(5000);
}

static async Task MyTask()
{
    await MyMiniTask();
    Console.WriteLine("Do Task...");
}

static async Task MiniTask()
{
    await Task.Delay(1000);
    Console.WriteLine("Do Mini Task...");
}

output:

Do main work...
Do Mini Task...
Do Task...

As I understand it, the code should run like this:

  • Run program -> Main thread is initialized to run the program.
  • Task.Run(MyTask) -> thread A in the thread pool will handle MyTask.
  • In the output, print out “Do main work…” first, even though the console WriteLine is written after Task.Run(MyTask). The reason is because the Main thread and thread A are two different threads, so they will be executed in parallel.
  • Back to thread A and MyTask, it encounters the statement: await MiniTask -> thread B in the thread pool will handle MiniTask (a new thread will always be used to handle MiniTask even if there is no await).
  • Because of using await, MyTask will have to wait for MiniTask to complete, and while waiting, thread A of MyTask does not handle anything -> MyTask will be marked as "a pause point" here and C# will release thread A back to the thread pool, thread A can now do another job.
  • When MiniTask is completed, C# will return to "the pause point" of MyTask, and handle it with another thread in the ThreadPool (it could be thread A or any other free thread).

=> The meaning of using async await is: it will wait for the result of the asynchronous task (MiniTask), the await keyword when used will release the thread of the method that calls it (Thread A of MyTask), and ThreadPool will allocate another thread to continue processing this method after MiniTask has completed.

=> There is a difference between using the Wait() method of Task and the keyword await, which is Wait() will not release the thread of the method that calls it (I have tried).

=> Summary (according to my understanding):

  • When you want to perform multiple tasks in parallel without affecting the main thread -> use Thread, and now more modern is Task.
  • When you want to wait for the result of a Task -> Wait() it.
  • When you want to wait for the result of a Task, but want to release the Thread of the method that calls that Task in the waiting time -> await it.

I don't know if I understand that right?
Sorry if my English is not good

This example code actually works and prints the output as above.
But I don't know if it works the way I think or just a coincidence.

英文:

I’m currently learning about C#, I’m wondering how Thread, Task, async and await really work. This is what I understand:

  • Task.Run(MyTask) is always executed on a new thread (in the thread pool)
  • Because of this, Task will run in parallel with the method that calls it (because they are on two different threads)
  • Therefore, use await to wait for the result of that Task, then continue executing the code below.
  • This is my example code:
static void Main(string[] args)
{
    Task.Run(MyTask);
    Console.WriteLine("Do main work...");
    Thread.Sleep(5000);
}

static async Task MyTask()
{
    await MyMiniTask();
    Console.WriteLine("Do Task...");
}

static async Task MiniTask()
{
    await Task.Delay(1000);
    Console.WriteLine("Do Mini Task...");
}

output:<br>
Do main work...<br>
Do Mini Task...<br>
Do Task...<br>
As I understand it, the code should run like this:

  • Run program -> Main thread is initialized to run the program
  • Task.Run(MyTask) -> thread A in the thread pool will handle MyTask
  • In the output, print out “Do main work…” first, even though the console writeline is written after Task.Run(MyTask). The reason is because Main thread and thread A are two different threads, so they will be executed in parallel
  • Back to thread A and MyTask, it encounters the statement: await MiniTask -> thread B in the thread pool will handle MiniTask (a new thread will always be used to handle MiniTask even if there is no await)
  • Because of using await, MyTask will have to wait for MiniTask to complete, and while waiting, thead A of MyTask does not handle anything -> MyTask will be marked as "a pause point" here and C# will release thread A back to the thread pool, thread A can now do another job
  • When MiniTask is completed, C# will return to "the pause point" of MyTask, and handle it with another thread in the ThreadPool (it could be thread A or any other free thread)

<br> => The meaning of using async await is: it will wait for the result of the asynchronous task (MiniTask), await keyword when used will release the thread of the method that calls it (Thread A of MyTask), and ThreadPool will allocate another thread to continue processing this method after MiniTask has completed.
<br>There is a difference between using the Wait() method of Task and the keyword await, which is Wait() will not release the thread of the method that calls it (I have tried)
<br>
=>> Summary (according to my understanding):

  • When you want to perform multiple tasks in parallel without affecting the main thread -> use Thread, and now more modern is Task
  • When you want to wait for the result of a Task -> Wait() it
  • When you want to wait for the result of a Task, but want to release the Thread of the method that calls that Task in the waiting time -> await it

<br>I don't know if I understand that right?
<br> Sorry if my English is not good

This example code actually works and prints the output as above.
But I don't know if it works the way I think or just a coincidence.

答案1

得分: 2

您的理解基本正确。需要纠正的一个点是:

Task.Run(MyTask) 总是在一个新线程上执行(在线程池中)

不是在一个新线程上。拥有一个ThreadPool的整个目的是重用少量线程,以避免每次需要线程执行微小工作时都要付出创建新线程的代价。所以它只是一个线程,而不是一个新线程。

英文:

Your understanding is mostly OK. One point that needs to be corrected is here:

> Task.Run(MyTask) is always executed on a new thread (in the thread pool)

Not on a new thread. The whole point of having a ThreadPool is to reuse a small number of threads, in order to avoid paying the cost of creating a new thread each time a thread is needed to do some minuscule work. So it's just a thread, not a new thread.

huangapple
  • 本文由 发表于 2023年7月23日 14:12:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/76746848.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定