【问题标题】:Clarification needed on async and await需要澄清 async 和 await
【发布时间】:2013-09-30 21:34:29
【问题描述】:

我阅读了很多关于 async 和 await 的文章(主要来自 msdn - 实际上这很好)。还有一个问题困扰着我,我找不到答案。

如果任务上有等待语句,则控件将返回给它的调用者,直到它在调用者中再次被等待。在那种情况下,这个耗时的任务是否会在单独的线程中执行?如果不是,那么它如何与主线程并行执行。

async Task<string> GetContentsAsync()
{
    int sample = 0;
    HttpClient client = new HttpClient();
    Task<string> contents = client.GetStringAsync("http://www.microsoft.com");
            
    string data = await contents;
    return data;
}

我希望我的问题很清楚。

【问题讨论】:

标签: c# async-await


【解决方案1】:

在那种情况下,这个耗时的任务会在单独的线程中执行吗?

有两种任务。一些Tasks 有代码要执行,它们在某个线程上运行。其他Tasks不执行代码;它们只是代表一些未来的事件。

async 经常使用“事件任务”很多,尤其是在 I/O 场景中。在您的示例中,您正在执行 HTTP GET。 GetStringAsync 将发送 HTTP 请求,然后返回一个在收到响应时完成的“事件任务”。当 HTTP 请求在传输中并由服务器处理时,没有代码 供客户端为该请求执行。所以不需要线程,也没有使用任何线程。

另见我的回答here。

【讨论】:

    【解决方案2】:

    这取决于任务是如何创建的,但是不,任务并不是固有地在单独的线程上自动执行的。一些帮助方法,例如 Task.Run,可以帮助您确保将任务放在单独的线程(在本例中为线程池)。

    请记住,GUI 应用程序,特别是 WinForms,运行所谓的事件循环。在 WinForms 中,这发生在您背后,在 Application.Run 调用中。此事件循环接收点击等事件并调用您的处理程序。执行此循环的线程称为“GUI 线程”。在 WinForms 中,它是创建所有控件的线程,因此也是唯一允许触摸这些控件的线程。

    当您在方法上使用async 修饰符创建任务时,该代码也被安排通过此事件循环执行。它只是排队。就像以前的 Invoke 电话一样。因此,一旦您的事件处理程序返回,事件循环最终会到达排队的任务,执行它,然后执行await 之后的其余方法。这里没有并行性。

    但是,还有其他方法可以创建任务;调用async 方法只是一种方法。 Task.Run 创建放在不同线程上的任务。您在示例中显示的GetStringAsync 实际上将与调用任务的任何线程并行运行。

    【讨论】:

    • 如果我没有明确使用 Task.Run 在这种情况下它是如何执行的?
    • 在我提供的示例代码中执行如何?
    • 与平行度正交?
    • @Liam 我的意思是,无论您是否使用异步,以及是否使用并行,都是独立的概念。试试看;创建一个异步按钮处理程序,另一个修改 GUI 的异步方法,并从前者等待后者。您会看到这里的所有方法都将在 GUI 线程上执行。并行度为零,但使用异步。
    • @ckv 是的,它在一个线程中运行——这是一个被称为“GUI 线程”的重要线程;唯一允许修改 UI 控件的线程。
    猜你喜欢
    • 2017-10-29
    • 2021-04-27
    • 1970-01-01
    • 1970-01-01
    • 2011-11-09
    • 2012-07-18
    • 1970-01-01
    • 2023-03-09
    • 1970-01-01
    相关资源
    最近更新 更多