6

在过去的 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()是同步调用的(即控制在调用时不会立即返回)。但是在名为“三”的行中,运行时将返回控制权。

我的问题是:

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

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

  3. 如果AccessTheWebAsync()做了一些计算密集型的事情,比如运行一个具有无数次迭代的循环,则控制只会在循环完成时返回给调用者。是对的吗?

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

  5. 调用没有等待的异步方法(假设它是可能的)与调用非异步方法相同吗?

4

2 回答 2

5

await首先很重要的一点:如果要等待的任务尚未完成,运行时才会返回给调用者。

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

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

来源

问题2:也许在实施中,GetStringAsync但我们不知道,我们也不必知道。我们知道在GetStringAsync不阻塞线程的情况下以某种方式获得结果就足够了。

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

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

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

您不需要asyncandawait关键字。例子:

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

问题5:我再引用一次

async 方法通常包含一个或多个 await 运算符,但没有 await 表达式不会导致编译器错误。如果 async 方法不使用 await 运算符来标记暂停点,则该方法会像同步方法一样执行,尽管有 async 修饰符。编译器会针对此类方法发出警告。

来源(与以前相同的页面,只是不同的部分)

于 2013-06-07T09:01:43.537 回答
3

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

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

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

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

如果AccessTheWebAsync()做了一些计算密集型的事情,比如运行一个具有无数次迭代的循环,则控制只会在循环完成时返回给调用者。是对的吗?

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

在异步函数中,有没有办法立即返回控制,然后在后台线程中继续工作?

你应该使用Task.Run()它。

调用没有等待的异步方法(假设它是可能的)与调用非异步方法相同吗?

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

于 2013-06-07T10:58:26.327 回答