Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/307.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 与ConfigureAwait'异步/等待;s continueOnCapturedContext参数和异步继续的SynchronizationContext_C#_Asynchronous_Task Parallel Library_Async Await_Synchronizationcontext - Fatal编程技术网

C# 与ConfigureAwait'异步/等待;s continueOnCapturedContext参数和异步继续的SynchronizationContext

C# 与ConfigureAwait'异步/等待;s continueOnCapturedContext参数和异步继续的SynchronizationContext,c#,asynchronous,task-parallel-library,async-await,synchronizationcontext,C#,Asynchronous,Task Parallel Library,Async Await,Synchronizationcontext,我想先把代码放在前面,然后解释情况,并基于此提出我的问题: public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private async void Button_Click_2(object sender, RoutedEventArgs e) { var result = await GetValuesA

我想先把代码放在前面,然后解释情况,并基于此提出我的问题:

public partial class MainWindow : Window {

    public MainWindow() {
        InitializeComponent();
    }

    private async void Button_Click_2(object sender, RoutedEventArgs e) {

        var result = await GetValuesAsync();
        Foo.Text += result;
    }

    public async Task<string> GetValuesAsync() {           

        using (var httpClient = new HttpClient()) {

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


            // This is the continuation for the httpClient.GetAsync method.
            // We shouldn't get back to sync context here
            // Cuz the continueOnCapturedContext is set to *false*
            // for the Task which is returned from httpClient.GetAsync method
            var html = await GetStringAsync();

            // This is the continuation for the GetStringAsync method.
            // Should I get back to sync context here?
            // Cuz the continueOnCapturedContext is set to *true*
            // for the Task which is returned from GetStringAsync 

            // However, GetStringAsync may be executed in another thread
            // which has no knowledge for the sync context 
            // because the continueOnCapturedContext is set to *false*
            // for the Task which is returned from httpClient.GetAsync method.

            // But, on the other hand, GetStringAsync method also has a 
            // chance to be executed in the UI thread but we shouldn't be
            // relying on that. 
            html += "Hey...";
            Foo.Text = html;

            return html;
        }
    }

    public async Task<string> GetStringAsync() {

        await Task.Delay(1000);
        return "Done...";
    }
}
公共部分类主窗口:窗口{
公共主窗口(){
初始化组件();
}
专用异步无效按钮\u单击\u 2(对象发送方,路由目标){
var result=await GetValuesAsync();
Foo.Text+=结果;
}
公共异步任务GetValuesAsync(){
使用(var httpClient=new httpClient()){
var response=wait-httpClient
.GetAsync(“http://www.google.com")
.ConfigureAwait(continueOnCapturedContext:false);
//这是httpClient.GetAsync方法的延续。
//我们不应该回到同步上下文
//因为continueOnCapturedContext被设置为*false*
//对于从httpClient.GetAsync方法返回的任务
var html=await GetStringAsync();
//这是GetStringAsync方法的延续。
//我应该回到同步上下文吗?
//因为continueOnCapturedContext设置为*true*
//对于从GetStringAsync返回的任务
//但是,GetStringAsync可以在另一个线程中执行
//它不知道同步上下文
//因为continueOnCapturedContext设置为*false*
//对于从httpClient.GetAsync方法返回的任务。
//但是,另一方面,GetStringAsync方法也有一个
//有可能在UI线程中执行,但我们不应该
//靠这个。
html+=“嘿…”;
Text=html;
返回html;
}
}
公共异步任务GetStringAsync(){
等待任务。延迟(1000);
返回“完成…”;
}
}
这是一个在.NET4.5上运行的相当简单的WPF示例,可能没有多大意义,但这应该可以帮助我解释我的情况

我在屏幕上有一个按钮,它有一个异步点击事件。当您查看
GetValuesAsync
代码时,您将看到
wait
关键字的用法两次。第一次使用时,我将
任务的
continueOnCapturedContext
参数设置为
false。因此,这表明我不一定希望在
SynchronizationContext.Current
中执行我的延续。到目前为止还不错

在第二次使用
await
时(使用
GetStringAsync
方法),我没有调用
ConfigureAwait
方法。因此,我基本上表示我希望回到当前的同步上下文,继续使用
GetStringAsync
方法。如您所见,我尝试在continuation中设置
TextBlock.Text
(属于UI线程)属性

当我运行应用程序并单击按钮时,会出现异常,并显示以下消息:

调用线程无法访问此对象,因为另一个 线程拥有它

起初,这对我来说毫无意义,我认为我发现了一个bug,但后来,我意识到
GetStringAsync
可能会在另一个线程中执行(很可能)它与UI线程不同,并且不知道同步上下文,因为从
httpClient.GetAsync
方法返回的
任务的
continueOnCapturedContext
设置为
false

这里是这样吗?另外,在这种情况下,是否有可能将
GetStringAsync
方法发回UI线程,因为httpClient.GetAsync方法延续可能在UI线程内执行


我在代码中也有一些注释。鉴于我的问题和代码中的注释,我是否遗漏了什么?

当您调用
ConfigureAwait(false)
时,该方法的其余部分将在线程池线程上执行,除非您正在等待的
任务已经完成

由于
GetAsync
几乎肯定会异步运行,因此我希望
GetStringAsync
在线程池线程上运行

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;
    }
}
公共异步任务GetValuesAsync(){
使用(var httpClient=new httpClient()){
var response=wait-httpClient
.GetAsync(“http://www.google.com")
.ConfigureAwait(continueOnCapturedContext:false);
//现在我们在线程池线程上。
//此“等待”将捕获当前SynchronizationContext。。。
var html=await GetStringAsync();
//…然后在这里继续。
//但这不是UI SynchronizationContext。
//这是线程池同步上下文。
//所以我们回到了线程池线程。
//因此,这将引发一个例外。
html+=“嘿…”;
Text=html;
返回html;
}
}
此外,在这种情况下,GetStringAsync方法是否有可能被发回UI线程,因为httpClient.GetAsync方法延续可能在UI线程内执行

在UI线程上运行
GetStringAsync
的唯一方法是
GetAsync
在实际执行
wait
ed之前完成。可能性很小


因此,如果不再需要上下文,我更愿意对每个
wait
使用
configurewait(false)

谢谢!你的最后一句话是我考虑的方式(我已经,但现在我要坚持更多)。这不会产生明显的区别,但使用
ConfigureAwait(false)
也可以避免不必要的
Synchroni