C# Language
Async-Awaitの同期コンテキスト
サーチ…
async / awaitキーワードの擬似コード
単純な非同期メソッドを考えてみましょう:
async Task Foo()
{
Bar();
await Baz();
Qux();
}
単純化すると、このコードは実際には次のことを意味します。
Task Foo()
{
Bar();
Task t = Baz();
var context = SynchronizationContext.Current;
t.ContinueWith(task) =>
{
if (context == null)
Qux();
else
context.Post((obj) => Qux(), null);
}, TaskScheduler.Current);
return t;
}
これは、 async
/ await
キーワードが存在する場合、現在の同期コンテキストを使用することを意味します。つまり、UI、Web、およびConsoleアプリケーションで正しく動作するライブラリコードを記述できます。
ソース記事 。
同期コンテキストを無効にする
同期コンテキストを無効にするには、 ConfigureAwait
メソッドを呼び出す必要があります。
async Task() Foo()
{
await Task.Run(() => Console.WriteLine("Test"));
}
. . .
Foo().ConfigureAwait(false);
ConfigureAwaitは、デフォルトのSynchronizationContext取得動作を回避する手段を提供します。 flowContextパラメータにfalseを渡すと、待機した後にSynchronizationContextを使用して実行を再開できなくなります。
それはSynchronizationContextに関するすべてです。
なぜSynchronizationContextが重要なのでしょうか?
この例を考えてみましょう。
private void button1_Click(object sender, EventArgs e)
{
label1.Text = RunTooLong();
}
このメソッドは、 RunTooLong
が完了するまでUIアプリケーションをフリーズします。アプリケーションが応答しなくなります。
内部コードを非同期で実行することができます:
private void button1_Click(object sender, EventArgs e)
{
Task.Run(() => label1.Text = RunTooLong());
}
しかし、このコードは内部ボディが非UIスレッドで実行される可能性があり、UIプロパティを直接変更してはならないため、このコードは実行されません。
private void button1_Click(object sender, EventArgs e)
{
Task.Run(() =>
{
var label1Text = RunTooLong();
if (label1.InvokeRequired)
lable1.BeginInvoke((Action) delegate() { label1.Text = label1Text; });
else
label1.Text = label1Text;
});
}
今このパターンを使うことを常に忘れないでください。または、 SynchronizationContext.Post
を試してみてください。
private void button1_Click(object sender, EventArgs e)
{
Task.Run(() =>
{
var label1Text = RunTooLong();
SynchronizationContext.Current.Post((obj) =>
{
label1.Text = label1 Text);
}, null);
});
}
Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow