我不明白在使用 async-await 时控制是如何返回给调用者的,因为当我执行这段代码时,第一个线程在等待方法中调用任务时实际上被销毁了,而给出结果的线程执行所有剩余的代码。下面我也画了一个图表,说明我认为执行的方式,但似乎是错误的。
根据“将控制权返回给调用者”假设的工作流:
结果
主要
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/