C# 异步编程控制流

C# 异步编程控制流,c#,async-await,C#,Async Await,在过去的两天里,我一直在阅读有关c#async方法的文章,据我所知,与thread(threadpool.queueuserworkitem())不同的是,对异步方法的调用不会立即返回,它只会在被调用的方法遇到等待或完成(或异常)时返回 请参见下面的示例 public partial class MainWindow : Window { // . . . private async void startButton_Click(object sender, RoutedEven

在过去的两天里,我一直在阅读有关c#async方法的文章,据我所知,与thread
(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;
    }
} 
公共部分类主窗口:窗口
{
// . . .
私有异步无效开始按钮单击(对象发送方,路由目标)
{
//一个
Task getLengthTask=AccessTheWebAsync();
//四
int contentLength=等待getLengthTask;
//六
结果文本框+=
格式(“\r\n下载字符串的长度:{0}.\r\n”,contentLength);
}
异步任务访问WebAsync()
{
//两个
HttpClient=新的HttpClient();
任务getStringTask=
client.GetStringAsync(“http://msdn.microsoft.com");
//三
字符串urlContents=等待getStringTask;
//五
返回urlContents.Length;
}
} 
从我收集的信息来看,在上面的代码中,
AccessTheWebAsync()
是同步调用的(即控件在调用时不会立即返回)。但在名为“三”的行中,运行时将返回控制

我的问题是:

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

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

  • 如果
    AccessTheWebAsync()
    做了一些计算密集型的事情,比如运行了无数次迭代的循环,那么控件只会在循环完成后返回给调用方。是这样吗

  • 在异步函数中,有没有一种方法可以立即返回控件,然后在后台线程中继续工作?(就像调用threadpool.queueuserworkitem()一样)

  • 调用一个不带wait的异步方法(假设可能)与调用一个非异步方法相同吗


  • 首先,重要的一点是:只有在等待的任务尚未完成时,运行时才会在
    await
    上返回调用方

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

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

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

    问题3:如果循环放在
    wait
    关键字之前,则为“是”

    问题4:引述与以前相同的段落:

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

    您不需要使用
    async
    wait
    关键字。例如:

    private Task<int> DoSomethingAsync()
    {
        return Task.Run(() =>
        {
            // Do CPU heavy calculation here. It will be executed in the thread pool.
            return 1 + 1;
        });
    }
    
    private Task DoSomethingAsync()
    {
    返回任务。运行(()=>
    {
    //在这里进行CPU密集型计算。它将在线程池中执行。
    返回1+1;
    });
    }
    
    问题5:我将再次引用

    异步方法通常包含一个或多个等待运算符,但缺少等待表达式不会导致编译器错误。如果异步方法不使用wait操作符来标记挂起点,则尽管使用了异步修饰符,该方法仍会像同步方法一样执行。编译器会对此类方法发出警告

    (与前一页相同,只是不同部分)

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

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

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

    没有。除非您另外指定(请参见上文),
    wait
    将恢复到捕获的上下文,在您的情况下,该上下文就是UI线程

    如果
    AccessTheWebAsync()
    做了一些计算密集型的事情,比如运行了无数次迭代的循环,那么控件只会在循环完成后返回给调用方。是这样吗

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

    在异步函数中,有没有一种方法可以立即返回控件,然后在后台线程中继续工作

    为此,应该使用
    Task.Run()

    调用一个不带wait的异步方法(假设可能)与调用一个非异步方法相同吗

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