简体   繁体   English

C#异步等待从未返回主线程

[英]C# Async Await never returns to main thread

I wrote a really simple check that tells me what thread I am on and then added some async await code. 我写了一个非常简单的检查,告诉我我在哪个线程上,然后添加了一些异步等待代码。 I noticed that the first time I check I am on thread1, then thread3, and I never return to thread1 during my code execution. 我注意到,我第一次检查自己在线程1上,然后在线程3上,并且在执行代码期间我从未返回线程1。

Can anyone explain to me why after the await I don't return to the main thread that called await? 谁能向我解释为什么在等待之后我不返回到调用等待的主线程? The output of WhatThreadAmI() goes as follows: WhatThreadAmI()的输出如下:

**********************
Main - 17 -- True
**********************
**********************
CountAsync - 37 -- False
**********************
**********************
Main - 22 -- False
**********************
**********************
Main - 29 -- False
**********************

Example code: 示例代码:

class Program
{
    static Thread mainThread;
    public static async Task Main(string[] args)
    {
        mainThread = Thread.CurrentThread;


        WhatThreadAmI();

        Console.WriteLine("Counting until 100 million in 5 seconds ...");
        var msWait = await CountAsync();

        WhatThreadAmI();
        Console.WriteLine($"Counting to 100 million took {msWait} milliseconds.");


        Console.WriteLine("Press any key to exit");
        Console.ReadKey();

        WhatThreadAmI();
    }


    static async Task<String> CountAsync()
    {
        return await Task.Run(() =>
        {
            WhatThreadAmI();
            Task.Delay(TimeSpan.FromSeconds(5)).Wait();
            var startTime = DateTime.Now;

            var num = 0;

            while (num < 100000000)
            {
                num += 1;
            }

            return (DateTime.Now - startTime).TotalMilliseconds.ToString();

        });
    }


    static void WhatThreadAmI([CallerMemberName]string Method = "", [CallerLineNumber]int Line = 0)
    {
        const string dividor = "**********************";

        Debug.WriteLine(dividor);
        Debug.WriteLine($"{Method} - {Line} -- {IsMainThread()}");
        Debug.WriteLine(dividor);
    }

    public static bool IsMainThread() => mainThread == Thread.CurrentThread;

}

await will capture current synchronization context ( SynchronizationContext.Current ) and post continuation (everything after await ) to that context (unless you use ConfigureAwait(false) ). await将捕获当前的同步上下文( SynchronizationContext.Current )并将后续过程( await之后的所有内容)发布到该上下文中(除非您使用ConfigureAwait(false) )。 If there is no synchronization context, like in console application (your case) - by default continuation will be scheduled to thread pool thread. 如果没有同步上下文,例如在控制台应用程序中(在您的情况下)-默认情况下,将继续计划线程池线程的继续。 Your main thread is not thread pool thread, so you will never return to it in code you posted. 您的主线程不是线程池线程,因此您永远不会在发布的代码中返回它。

Note that every synhronization context implementation can decide what to do with callbacks posted to it, it does not necessary for it to post callback to single thread (like WPF\\WinForms synchronization contexts do). 注意,每个同步上下文实现都可以决定如何处理发布到其上的回调,而不必将回调发布到单线程中(就像WPF \\ WinForms同步上下文一样)。 So even with synchronization context you are not guaranteed to "return back to caller thread". 因此,即使使用同步上下文,也不能保证“返回到调用者线程”。

Even though you can now have async main functions there still no OperationContext for console applications. 即使您现在可以具有异步主要功能,但控制台应用程序仍没有OperationContext。 Because of that it will use the default task scheduler which will cause continuations after an await to use any thread pool thread instead of the original thread associated with the OperationContext. 因此,它将使用默认的任务计划程序,这将导致在等待使用任何线程池线程而不是与OperationContext关联的原始线程后继续执行。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM