Saya pikir Anda membuat beberapa hal bingung, di sini. Apa yang Anda minta sudah mungkin digunakan System.Threading.Tasks
, async
dan await
pada C # 5 hanya akan memberikan sedikit gula sintaksis yang lebih baik untuk fitur yang sama.
Mari kita gunakan contoh Winforms - jatuhkan tombol dan kotak teks di formulir dan gunakan kode ini:
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;
}
Jalankan dan Anda akan melihat bahwa (a) tidak memblokir utas UI dan (b) Anda tidak mendapatkan kesalahan "operasi lintas-benang yang tidak sah" seperti biasa - kecuali Anda menghapus TaskScheduler
argumen dari yang terakhir ContinueWith
, di yang mana Anda akan.
Ini adalah gaya passing kelanjutan standar-rawa . Keajaiban terjadi di TaskScheduler
kelas dan khususnya instance diambil oleh FromCurrentSynchronizationContext
. Lewati ini ke kelanjutan apa pun dan Anda memberi tahu bahwa kelanjutan harus berjalan pada utas apa pun yang disebut FromCurrentSynchronizationContext
metode - dalam hal ini, utas UI.
Penunggu sedikit lebih canggih dalam arti bahwa mereka menyadari utas mana yang mereka mulai dan utas mana kelanjutan yang perlu terjadi. Jadi kode di atas dapat ditulis sedikit lebih alami:
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;
}
Kedua harus terlihat sangat mirip, dan pada kenyataannya mereka yang sangat mirip. The DelayedAddAsync
Metode sekarang mengembalikan Task<int>
bukan sebuah int
, sehingga await
hanya menampar lanjutan ke setiap salah satu dari mereka. Perbedaan utama adalah bahwa ia meneruskan konteks sinkronisasi pada setiap baris, jadi Anda tidak harus melakukannya secara eksplisit seperti yang kami lakukan pada contoh terakhir.
Secara teori perbedaannya jauh lebih signifikan. Dalam contoh kedua, setiap baris tunggal dalam button1_Click
metode ini sebenarnya dieksekusi di utas UI, tetapi tugas itu sendiri ( DelayedAddAsync
) berjalan di latar belakang. Pada contoh pertama, semuanya berjalan di latar belakang , kecuali untuk penugasan textBox1.Text
yang telah kami lampirkan secara eksplisit ke konteks sinkronisasi utas UI.
Itulah yang benar-benar menarik await
- fakta bahwa seorang penunggu dapat masuk dan keluar dari metode yang sama tanpa memblokir panggilan. Anda panggil await
, utas saat ini kembali ke pemrosesan pesan, dan ketika selesai, penunggu akan mengambil tepat di mana itu tinggalkan, di utas yang sama ditinggalkan di. Tapi dalam hal Anda Invoke
/ BeginInvoke
kontras dalam pertanyaan, saya Saya menyesal mengatakan bahwa Anda seharusnya sudah berhenti melakukan itu sejak lama.
await
fungsi. Ini hanya banyak gula sintaksis untuk kelanjutan lewat . Mungkin ada beberapa perbaikan lain yang tidak terkait dengan WinForms yang seharusnya membantu? Itu akan jatuh di bawah kerangka NET. Itu sendiri, meskipun, dan bukan C # khusus.