为什么在等待方法之后代码上没有使用初始线程?

时间:2018-02-14 11:06:04

标签: c# multithreading async-await

我不明白在使用async-await时控件是如何返回给调用者的,因为当我执行这段代码时,第一个线程在等待方法中调用task时几乎被破坏,并且执行结果的线程执行剩下的所有代码。我还画了一个关于我如何看待执行的图表,但似乎是错误的。

根据&#34假设工作流程;将控制权交还给来电者":

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;
           }

任何人都可以指出我正确的方向吗?还有什么原因导致新线程产生?总是在启动任务时?还有其他&#34;触发器&#34;除了创建将执行剩余代码的新线程的任务?

1 个答案:

答案 0 :(得分:5)

async主方法转换为类似的东西:

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

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

考虑到这一点,在&#34;来自主要的异步呼叫之前&#34;指出你是主应用程序线程(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才会被销毁&#34;)。