本文介绍了异步/等待与ConfigureAwait的continueOnCapturedContext参数的SynchronizationContext异步延续的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想先放code,然后说明情况,问我的问题基于:

 公共部分类主窗口:窗口{    公共主窗口(){
        的InitializeComponent();
    }    私人异步无效Button_Click_2(对象发件人,RoutedEventArgs E){        VAR的结果=等待GetValues​​Async();
        Foo.Text + =结果;
    }    公共异步任务<串GT; GetValues​​Async(){        使用(VAR的HttpClient =新的HttpClient()){            VAR响应=等待的HttpClient
                .GetAsync(http://www.google.com)
                .ConfigureAwait(continueOnCapturedContext:假);
            //这是httpClient.GetAsync方法的延续。
            //我们不应该回到这里环境同步
            //的Cuz continueOnCapturedContext设置为* *假
            //为这是从httpClient.GetAsync方法返回的任务
            VAR HTML =等待GetStringAsync();            //这是GetStringAsync方法的延续。
            //我应该回到这里同步语境?
            //的Cuz continueOnCapturedContext设置为*真*
            //对于其从GetStringAsync返回的任务            //然而,GetStringAsync可以在另一线程中执行
            //它可以对同步上下文中没有的知识
            //因为continueOnCapturedContext设置为* *假
            //为这是从httpClient.GetAsync方法返回的任务。            //但是,在另一方面,GetStringAsync方法也有一个
            //机会在UI线程中执行,但我们不应该
            //依靠这一点。
            HTML + =嘿嘿......;
            Foo.Text = HTML;            返回HTML;
        }
    }    公共异步任务<串GT; GetStringAsync(){        等待Task.Delay(1000);
        返回完成......;
    }
}

这是运行在.NET 4.5,可能不会使一个很大的意义,但是这应该帮我解释一下我的情况相当简单的WPF样本。

我有具有异步点击事件,屏幕上的按钮。当你在看 GetValues​​Async code,你会看到的await 关键字的使用两次。有了第一次使用,我设置 continueOnCapturedContext Task.ConfigureAwait 方法的参数。所以,这表明我的不一定要将里面的 SynchronizationContext.Current 执行我的延续。到目前为止好。

在第二个的await 使用(与 GetStringAsync 方法),我没有叫 ConfigureAwait 方法。所以,我基本上表示,我想即可回到当前的同步上下文的 GetStringAsync 方法的延续。所以,你可以看到,我尝试设置延续在 TextBlock.Text (属于UI线程)属性。

当我运行应用程序,并单击按钮,我得到一个异常让我有以下消息:

At first, this made no sense to me and I thought that I discovered a bug but then, I realized that GetStringAsync may be executed in another thread (highly likely) which is different than the UI thread and has no knowledge for the sync context because the continueOnCapturedContext is set to false for the Task which is returned from httpClient.GetAsync method.

Is this the case here? Also, in this case, is there a chance for GetStringAsync method to be posted back to UI thread bacuse the httpClient.GetAsync method continuation may be executed inside the UI thread?

I have also a few comments inside the code. In view of my questions and the comments inside the code, am I missing anything here?

解决方案

When you call ConfigureAwait(false), the rest of the method will be executed on a thread pool thread unless the Task you're awaiting is already complete.

Since GetAsync will almost definitely run asynchronously, I would expect GetStringAsync to run on a thread pool thread.

public async Task<string> GetValuesAsync() {           

    using (var httpClient = new HttpClient()) {

        var response = await httpClient
            .GetAsync("http://www.google.com")
            .ConfigureAwait(continueOnCapturedContext: false);

        // And now we're on the thread pool thread.

        // This "await" will capture the current SynchronizationContext...
        var html = await GetStringAsync();
        // ... and resume it here.

        // But it's not the UI SynchronizationContext.
        // It's the ThreadPool SynchronizationContext.
        // So we're back on a thread pool thread here.

        // So this will raise an exception.
        html += "Hey...";
        Foo.Text = html;

        return html;
    }
}

The only way GetStringAsync will run on the UI thread is if GetAsync completes before it's actually awaited. Highly unlikely.

For this reason, I prefer to use ConfigureAwait(false) for every await once the context is no longer needed.

这篇关于异步/等待与ConfigureAwait的continueOnCapturedContext参数的SynchronizationContext异步延续的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-27 00:15