异步编程控制流程

时间:2013-06-07 07:49:22

标签: c# async-await

我在过去2天内一直在阅读有关c#异步方法的内容,据我所知,与线程(threadpool.queueuserworkitem())不同,对异步方法的调用不会立即返回,只会在调用方法时返回等待或完成(或例外)

请参阅以下示例。

public partial class MainWindow : Window
{
    // . . .
    private async void startButton_Click(object sender, RoutedEventArgs e)
    {
        // ONE
        Task<int> getLengthTask = AccessTheWebAsync();

        // FOUR
        int contentLength = await getLengthTask;

        // SIX
        resultsTextBox.Text +=
            String.Format("\r\nLength of the downloaded string: {0}.\r\n", contentLength);
    }


    async Task<int> AccessTheWebAsync()
    {
        // TWO
        HttpClient client = new HttpClient();
        Task<string> getStringTask =
            client.GetStringAsync("http://msdn.microsoft.com");

        // THREE                 
        string urlContents = await getStringTask;

        // FIVE
        return urlContents.Length;
    }
} 

从我收集的内容中,在上面的代码中,AccessTheWebAsync()被同步调用(即,在调用时,控制不会立即返回)。但是在名为“THREE”的行中,运行时将返回控制权。

我的问题是:

  1. 运行时如何决定何时使用线程池或何时在调用线程中运行任务? (即执行代码而不返回控制权)

  2. 上面代码中的哪些点会使用新线程(或线程池)?

  3. 如果AccessTheWebAsync()执行计算密集型操作,例如运行具有无数次迭代的循环,则控件将仅在循环完成时返回到调用者。是吗?

  4. 在异步函数中,有没有办法立即返回控件然后继续在后台线程中执行工作? (就像我们调用了threadpool.queueuserworkitem())

  5. 调用异步方法而没有await(假设可能)与调用非异步方法相同吗?

2 个答案:

答案 0 :(得分:5)

首先重要的是:如果要等待的任务尚未完成,运行时将只返回await上的调用者。

问题1:我将在这里引用MSDN:

  

async和await关键字不会导致创建其他线程。异步方法不需要多线程,因为异步方法不能在自己的线程上运行。

Source

问题2:可能在GetStringAsync的实施中,但我们不知道,我们也不必知道它。这足以让我们知道GetStringAsync以某种方式得到它的结果而不会阻塞我们的线程。

问题3:如果循环放在await关键字之前,是的。

问题4:引用与之前相同的段落:

  

您可以使用Task.Run将CPU绑定的工作移动到后台线程

您不需要asyncawait个关键字。例如:

private Task<int> DoSomethingAsync()
{
    return Task.Run(() =>
    {
        // Do CPU heavy calculation here. It will be executed in the thread pool.
        return 1 + 1;
    });
}

问题5:我会再次引用

  

异步方法通常包含一个或多个await运算符,但缺少await表达式不会导致编译器错误。如果异步方法不使用await运算符来标记挂起点,则该方法将作为同步方法执行,尽管存在异步修饰符。编译器会发出此类方法的警告。

Source(与之前相同的页面,只是一个不同的部分)

答案 1 :(得分:3)

  

运行时如何决定何时使用线程池或何时在调用线程中运行任务?

如果存在同步上下文并且您没有明确指定您不想继续上下文(通过使用await task.ConfigureAwait(false)之类的内容),则该方法将在捕获的上下文上继续。在UI应用程序中,该上下文是UI线程,假设从UI线程调用该方法。

  

上面代码中的哪些点,将使用新线程(或线程池)?

无处。除非您另行指定(参见上文),否则await将恢复捕获的上下文,在您的情况下是UI线程。

  

如果AccessTheWebAsync()执行计算密集型操作,例如运行具有无数次迭代的循环,则控件将仅在循环完成时返回到调用者。是吗?

是的,假设循环在第一个“异步”await之前。 (await ed await已完成后,{Task也可以是“同步”。)

  

在异步函数中,有没有办法立即返回控件,然后继续以后台线程的形式进行工作?

您应该使用Task.Run()

  

在没有await的情况下调用异步方法(假设它可能)与调用非异步方法相同吗?

有可能,编译器会警告您该方法将完全同步执行。

相关问题