c# - 为什么在等待方法之后的代码中没有使用初始线程?

标签 c# multithreading async-await

我不明白在使用 async-await 时控制是如何返回给调用者的,因为当我执行这段代码时,第一个线程在等待方法中调用任务时实际上被销毁了,而给出结果的线程执行所有剩余的代码。下面我也画了一个图表,说明我认为执行的方式,但似乎是错误的。

根据“将控制权返回给调用者”假设的工作流:

Results

结果

enter image description here

主要

           public static string GetThreadId => Thread.CurrentThread.ManagedThreadId.ToString();

           static async Task Main(string[] args) {
                Console.WriteLine("From main before async call , Thread:" + GetThreadId);

                string myresult = await TestAsyncSimple();

                Console.WriteLine("From main after async call ,Thread:" + GetThreadId);
                Console.WriteLine("ResultComputed:" + myresult+",Thread:"+GetThreadId);
                Console.ReadKey();

            }

异步任务

         public static async Task<string> TestAsyncSimple() {

            Console.WriteLine("From TestAsyncSimple before delay,Thread:" + GetThreadId);
            string result=await Task.Factory.StartNew(() => {
                Task.Delay(5000);
                Console.WriteLine("From TestAsyncSimple inside Task,Thread:" + GetThreadId);
                return "tadaa";
                });
            Console.WriteLine("From TestAsyncSimple after delay,Thread:" + GetThreadId);
            return result;
           }

谁能指出我正确的方向?还有什么导致新线程产生?总是在启动任务时?除了创建将执行剩余代码的新线程的任务之外,还有其他“触发器”吗?

最佳答案

async Main 方法被转换成这样:

static void Main() {
    RealMain().GetAwaiter().GetResult();
}

static async Task RealMain() {
    // code from async Main
}

考虑到这一点,在“From main before async call”点你在主应用程序线程(id 1)上。这是常规(非线程池)线程。在

之前,您将一直在此线程上
await Task.Factory.StartNew(...)

此时,StartNew 启动一个新任务,该任务将在线程池线程上运行,线程池线程是创建的或从池中获取(如果可用)。这是您示例中的线程 3。

当您到达 await 时 - 控制权返回给调用者,在这种情况下调用者是线程 1。这个线程在重新等待 await 之后做什么?这里被屏蔽了:

 RealMain().GetAwaiter().GetResult();

等待 RealMain 的结果。

现在线程 3 已完成执行,但 TestAsyncSimple() 还有更多代码要运行。如果在 await 之前没有同步上下文(这里的情况 - 在控制台应用程序中) - await 之后的部分将在可用的线程池线程上执行。由于线程 3 已完成其任务的执行 - 它可用并且能够继续执行其余的 TestAsyncSimple()Main() 函数,它确实这样做了。如上所述,线程 1 一直处于阻塞状态 - 因此它无法处理任何延续(它很忙)。此外,它也不是线程池线程(但这与此处无关)。

在您到达 Console.ReadKey 并按下一个键后 - Main 任务最终完成,线程 1(等待此任务完成)被解除阻塞,然后它从真正的 Main 函数和进程被终止(只有此时线程 1 被“销毁”)。

关于c# - 为什么在等待方法之后的代码中没有使用初始线程?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48785663/

相关文章:

c# - MVVM Light Call 属性更改的异步方法?

.net - Async Await 等待所有结果并继续

c# - 如何将字符串列表从 Sql 数据插入到 Document Db/cosmos db 中?

c# - 尝试在 C# 中连接到 Excel 电子表格

java - 在Java中等待所有线程完成

python - Python定时器可以通过检查它是否存在来取消吗?

c# - `async void`(没有等待)与 `void` 之间有什么区别

c# - c#中定时器的问题

c# - 错误 0004 : Could not load file or assembly 'MySql. 数据.Entity,版本=6.9.7.0

.NET 串行端口多线程