私は最初にコードを置き、次に状況を説明し、それに基づいて私の質問をしたいと思います:
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...";
}
}
これは、.NET 4.5で実行される非常に単純なWPFサンプルであり、おそらくあまり意味がありませんが、これは私の状況を説明するのに役立つはずです。
画面に非同期クリックイベントのあるボタンがあります。GetValuesAsync
コードを見ると、キーワードawait
の使用法が2回わかります。最初の使用では、メソッドcontinueOnCapturedContext
のパラメーターをに設定しました。したがって、これは、継続が内で実行されることを必ずしも望んでいないことを示しています。ここまでは順調ですね。Task.ConfigureAwait
false
SynchronizationContext.Current
await
(メソッドを使用した) 2回目の使用では、GetStringAsync
メソッドを呼び出しませんでしたConfigureAwait
。したがって、基本的に、メソッドを継続するために現在の同期コンテキストに戻りたいGetStringAsync
ことを示しました。ご覧TextBlock.Text
のとおり、継続内に(UIスレッドに属する)プロパティを設定しようとしています。
アプリケーションを実行してボタンをクリックすると、例外が発生し、次のメッセージが表示されます。
別のスレッドがオブジェクトを所有しているため、呼び出し元のスレッドはこのオブジェクトにアクセスできません。
最初はこれは意味がなく、バグを発見したと思いましたがGetStringAsync
、UIスレッドとは異なり、同期コンテキストの知識がない別のスレッド(可能性が高い)で実行される可能性があることに気付きました。メソッドから返されるcontinueOnCapturedContext
はに設定されfalse
ます。Task
httpClient.GetAsync
これはここに当てはまりますか?また、この場合、GetStringAsync
httpClient.GetAsyncメソッドの継続がUIスレッド内で実行される可能性があるため、メソッドがUIスレッドにポストバックされる可能性はありますか?
コード内にもいくつかコメントがあります。私の質問とコード内のコメントを考慮して、ここで何かが欠けていますか?