Async/await 和主线程

Async/await and main thread

提问人:Unnamed 提问时间:5/4/2023 最后编辑:Theodor ZouliasUnnamed 更新时间:10/30/2023 访问量:559

问:

我正在尝试了解异步等待行为,特别是它如何影响主线程,所以我的问题与以下代码有关:

    static async Task Main(string[] args)
    {
        await LongAction();
    }

    static Task LongAction() => Task.Delay(10000);

主线程在执行时会发生什么。据我了解,如果调用方线程不是主线程(我们称之为 thread2),则在可等待操作期间,该线程 (thread2) 将返回到(使用默认任务调度程序)。但是它会发生在主线程上吗(看起来不是这样,因为最初它不是从 TP 中获取的)?如果主线程是具有线程上下文的 UI 线程怎么办?LongActionThreadPool

C# 多线程 async-await 任务

评论

0赞 Jeroen van Langen 5/4/2023
UI 线程始终具有主循环。但是在你的例子上。通过支持 async 方法,调用者必须有一个循环,并循环直到 Task(由 main 返回)标记为已完成。在此示例中,该方法被标记为异步,因此它将变成状态机。当最后一个状态完成时,它将终止循环。main()
0赞 Unnamed 5/4/2023
对不起,你什么意思?loop
0赞 Jeroen van Langen 5/4/2023
一些初始代码调用 main 方法。
0赞 Unnamed 5/4/2023
对不起还是没听懂,你说的是编译器(状态机)生成的代码吗?
1赞 abolfazl sadeghi 5/4/2023
当您希望在不阻塞当前线程的情况下实现逻辑延迟时,请使用 await Task.Delay。.this 是了解 async-and-await 的站点:code-maze.com/...

答:

6赞 Stephen Cleary 5/4/2023 #1

特别是它如何影响主线程

async并且对任何特定类型的线程(包括主线程)都没有特殊行为。无论线程如何,它的行为方式都相同。但是,不同的框架确实会特别处理主线程。await

据我了解,如果调用方线程不是主线程(我们称之为 thread2),则在可等待操作期间,该线程 (thread2) 将返回到 ThreadPool(使用默认任务调度程序)。

的行为始终是相同的:如果可等待的(即任务)尚未完成,则返回。这取决于框架接下来如何处理该线程。如果是线程池线程,那么是的,该线程将返回到线程池。await

执行 LongAction 时主线程会发生什么情况。

.NET 运行时包括一个存根,该存根调用 -returning 方法,然后阻塞该线程,直到任务完成。这是必需的,因为在控制台应用程序中,如果主线程退出,应用程序也会退出。TaskMain

如果主线程是具有线程上下文的 UI 线程怎么办?

所有 UI 框架都有一个“消息循环”,用于处理有关用户输入和其他事件的消息。在这种情况下,线程只是返回到其主循环并继续处理其他事件。

评论

0赞 Unnamed 5/4/2023
非常感谢您的回答!我仍然对此没有信心:.- 如果初始/主线程不是从 ThreadPool 中获取的怎么办(我假设当您创建控制台应用程序时,主线程是通过接近 的东西创建的)。这个主线程只是休眠,不能重用?It's up to the framework what it does next with that thread. In the case of a thread pool thread, then yes, that thread is returned to the thread pool.new Thread
1赞 Stephen Cleary 5/4/2023
@Unnamed:如果你有一个 ,那么是的,线程只是阻塞,不能重复使用。async Main
1赞 Jeremy Lakeman 5/4/2023
程序的入口点不是 ,而是 dotnet 运行时提供的函数。运行时的工作是初始化操作系统未提供的任何语言功能,然后调用方法。在 的情况下,运行时函数将阻塞,直到任务完成。如果任务已经完成,那么就没有什么可等待的了。顺便说一句,用其他语言编写的程序也是如此,例如带有方法的 C 或 win32 程序,其中编译器提供了运行时入口点。MainMainasync Task MainWinMain
1赞 Stephen Cleary 5/4/2023
Is there any benefit in async workflow here comparing it with a sync call?它是异步的;如果您有一个仅限异步的 API,或者您正在对最终形式应为异步的代码进行原型设计,这将非常有用。它还允许异步并发(例如,)。如果只有一种方法,则在这种情况下,异步没有线程优势。Task.WhenAll
1赞 Charlieface 5/4/2023
“.NET 运行时包括一个调用返回任务的 Main 方法的存根” AFAIK 由 C# 编译器生成它,而不是运行时。dotnetfiddle.net/y1jaRB