C#5 async-awaitは非常に素晴らしいので、これを行う必要がないと聞いたことがあります。
if (InvokeRequired)
{
BeginInvoke(...);
return;
}
// do your stuff here
待機操作のコールバックが呼び出し元の元のスレッドで発生するようです。 Eric LippertとAnders Hejlsbergは、この機能はUI(特にタッチデバイスのUI)の応答性を高める必要性から生まれたと何度か述べています。
そのような機能の一般的な使用法は次のようになると思います:
public class Form1 : Form
{
// ...
async void GetFurtherInfo()
{
var temperature = await GetCurrentTemperatureAsync();
label1.Text = temperature;
}
}
コールバックのみが使用されている場合、ラベルテキストを設定すると、UIのスレッドで実行されないため、例外が発生します。
これまでのところ、これを確認するためのリソースは見つかりませんでした。これについて誰か知っていますか?これがどのように機能するかを技術的に説明する文書はありますか?
「はい」と答えるだけでなく、信頼できるソースからのリンクを提供してください。
ここでいくつか混乱していると思います。あなたが求めているのは、C#ではSystem.Threading.Tasks
、async
、await
を使用してすでに可能です5は、同じ機能にもう少し良い構文糖を提供するだけです。
Winformsの例を使用してみましょう-ボタンとテキストボックスをフォームにドロップし、次のコードを使用します。
private void button1_Click(object sender, EventArgs e)
{
Task.Factory.StartNew<int>(() => DelayedAdd(5, 10))
.ContinueWith(t => DelayedAdd(t.Result, 20))
.ContinueWith(t => DelayedAdd(t.Result, 30))
.ContinueWith(t => DelayedAdd(t.Result, 50))
.ContinueWith(t => textBox1.Text = t.Result.ToString(),
TaskScheduler.FromCurrentSynchronizationContext());
}
private int DelayedAdd(int a, int b)
{
Thread.Sleep(500);
return a + b;
}
それを実行すると、(a)UIスレッドがブロックされない、(b)TaskScheduler
を削除しない限り、通常の「クロススレッド操作が無効です」エラーが発生しないことがわかります。最後のContinueWith
からの引数。その場合はそうします。
これは沼地の標準 継続渡しスタイル です。魔法はTaskScheduler
クラス、特にFromCurrentSynchronizationContext
によって取得されたインスタンスで発生します。これを任意の継続に渡し、継続はFromCurrentSynchronizationContext
メソッドを呼び出したスレッド(この場合はUIスレッド)で実行する必要があることを伝えます。
ウェイターは、開始したスレッドと継続が発生する必要があるスレッドを認識しているという意味で、もう少し洗練されています。したがって、上記のコードは、より自然にlittleと書くことができます。
private async void button1_Click(object sender, EventArgs e)
{
int a = await DelayedAddAsync(5, 10);
int b = await DelayedAddAsync(a, 20);
int c = await DelayedAddAsync(b, 30);
int d = await DelayedAddAsync(c, 50);
textBox1.Text = d.ToString();
}
private async Task<int> DelayedAddAsync(int a, int b)
{
Thread.Sleep(500);
return a + b;
}
これらの2つは非常によく似ているはずです。実際、は非常によく似ています。 DelayedAddAsync
メソッドはint
ではなくTask<int>
を返すようになりました。そのため、await
は継続をそれぞれに継続しているだけです。主な違いは、各行の同期コンテキストに沿って渡されるため、前の例で行ったように明示的に行う必要がないことです。
理論的には、違いははるかに重要です。 2番目の例では、button1_Click
メソッドのすべての1行が実際にはUIスレッドで実行されますが、タスク自体(DelayedAddAsync
)はバックグラウンドで実行されます。最初の例では、everythingがbackgroundで実行され、exceptfor the UIスレッドの同期コンテキストに明示的にアタッチしたtextBox1.Text
への割り当て。
これがawait
の本当に興味深いところです。つまり、待機者が同じメソッドをブロック呼び出しなしでジャンプしたり、ジャンプしたりできるという事実です。 await
を呼び出すと、現在のスレッドがメッセージの処理に戻り、処理が完了すると、ウェイターは中断したところと同じスレッドで中断したところを正確にピックアップします。ただし、Invoke
/BeginInvoke
対照的に、あなたはずっと前にそれをやめるべきだったと申し訳ありません。
はい、UIスレッドの場合、待機操作のコールバックは呼び出し元の元のスレッドで発生します。
Eric Lippertは、1年前に8部構成のシリーズを書きました: Fabulous Adventures In Coding
編集:そしてここにAndersの// build /プレゼンテーションがあります: channel9
ところで、「// build /」を上下逆にすると「/ plinq //」になることに気づきましたか;-)
Jon SkeetがC#5の非同期メソッドをカバーする優れたプレゼンテーションを行いました。