Tôi muốn đặt mã đầu tiên và sau đó giải thích tình hình và yêu cầu câu hỏi của tôi dựa trên rằng:async/chờ đợi với tham số continueOnCapturedContext ConfigureAwait và SynchronizationContext cho continuations không đồng bộ
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...";
}
}
Đây là một mẫu WPF khá đơn giản mà chạy trên .NET 4.5 và có lẽ không có nhiều ý nghĩa nhưng điều này sẽ giúp tôi giải thích tình hình của tôi.
Tôi có một nút trên màn hình có sự kiện nhấp không đồng bộ. Khi bạn nhìn vào mã GetValuesAsync
, bạn sẽ thấy việc sử dụng từ khóa await
hai lần. Với lần sử dụng đầu tiên, tôi đặt thông số continueOnCapturedContext
của phương thức Task.ConfigureAwait
thành false
. Vì vậy, điều này chỉ ra rằng tôi không nhất thiết muốn tiếp tục của tôi được thực thi bên trong SynchronizationContext.Current
. Càng xa càng tốt.
Ở lần sử dụng thứ hai await
(với phương thức GetStringAsync
), tôi không gọi phương thức ConfigureAwait
. Vì vậy, về cơ bản tôi đã chỉ ra rằng tôi muốn để quay lại ngữ cảnh đồng bộ hóa hiện tại để tiếp tục phương thức GetStringAsync
. Vì vậy, như bạn có thể thấy, tôi cố gắng đặt thuộc tính TextBlock.Text
(thuộc về chủ đề giao diện người dùng) bên trong phần tiếp theo.
Khi tôi chạy ứng dụng và nhấp vào nút, tôi nhận được một ngoại lệ cho tôi được thông báo sau:
Các thread gọi không thể truy cập đối tượng này vì một khác nhau chủ đề sở hữu nó.
Lúc đầu, điều này không có ý nghĩa với tôi và tôi nghĩ rằng tôi đã phát hiện ra một lỗi nhưng sau đó, tôi nhận ra rằng GetStringAsync
có thể được thực hiện trong một thread (rất có khả năng) là khác nhau với thread UI và không có kiến thức về ngữ cảnh đồng bộ hóa vì continueOnCapturedContext
được đặt thành false
cho số Task
được trả về từ phương thức httpClient.GetAsync
.
Đây có phải là trường hợp ở đây không? Ngoài ra, trong trường hợp này, có một cơ hội cho phương thức GetStringAsync
được đăng lại cho chủ đề UI bacuse việc tiếp tục phương pháp httpClient.GetAsync có thể được thực thi bên trong chuỗi giao diện người dùng không?
Tôi cũng có một vài nhận xét bên trong mã. Theo quan điểm của các câu hỏi của tôi và các ý kiến bên trong mã, tôi có thiếu gì ở đây không?
Câu trả lời này có hữu ích không? http://stackoverflow.com/a/12357113/171121 –