ฉันคิดว่าคุณจะสับสนเล็กน้อยที่นี่ สิ่งที่คุณกำลังถามหาอยู่แล้วไปได้โดยใช้System.Threading.Tasks
การasync
และawait
ใน C # 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
ผู้รอดูมีความซับซ้อนมากขึ้นเล็กน้อยในแง่ที่ว่าพวกเขารู้ว่าพวกเขาเริ่มหัวข้อใดและหัวข้อใดที่ความต่อเนื่องต้องเกิดขึ้น ดังนั้นรหัสข้างต้นสามารถเขียนเล็ก ๆ น้อย ๆขึ้นตามธรรมชาติ:
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;
}
ทั้งสองควรมีลักษณะคล้ายกันมากและในความเป็นจริงพวกเขามีความคล้ายกันมาก DelayedAddAsync
วิธีการในขณะนี้จะส่งกลับTask<int>
แทนint
และเพื่อawait
เป็นเพียงการตบตบนหนึ่งในบรรดาแต่ละ ข้อแตกต่างที่สำคัญคือการส่งผ่านบริบทการซิงโครไนซ์ในแต่ละบรรทัดดังนั้นคุณไม่จำเป็นต้องทำอย่างชัดเจนเหมือนกับที่เราทำในตัวอย่างที่ผ่านมา
ในทางทฤษฎีแล้วความแตกต่างนั้นสำคัญกว่ามาก ในตัวอย่างที่สองทุกบรรทัดเดียวในbutton1_Click
วิธีจะถูกดำเนินการจริงในเธรด UI แต่งานของตัวเอง ( DelayedAddAsync
) ทำงานในพื้นหลัง ในตัวอย่างแรกทุกอย่างวิ่งในพื้นหลัง , ยกเว้นสำหรับการมอบหมายในการtextBox1.Text
ที่เราได้แนบอย่างชัดเจนกับบริบทการประสานหัวข้อ UI ของ
นั่นคือสิ่งที่น่าสนใจจริง ๆawait
- ความจริงที่ว่าผู้รอคอยสามารถกระโดดเข้าและออกจากวิธีเดียวกันโดยไม่ต้องมีการบล็อคการโทร คุณเรียกawait
ใช้เธรดปัจจุบันกลับไปที่การประมวลผลข้อความและเมื่อเสร็จแล้วผู้รอคอยจะรับสิ่งที่มันค้างไว้ในเธรดเดียวกันที่เหลืออยู่ แต่ในแง่ของInvoke
/ BeginInvoke
ความคมชัดในคำถามของฉัน ขออภัยที่ต้องบอกว่าคุณควรหยุดทำเช่นนั้นเป็นเวลานานแล้ว
await
ฟังก์ชั่นที่เกี่ยวข้อง มันเป็นเพียงแค่จำนวนมากของน้ำตาลประโยคสำหรับความต่อเนื่องผ่าน อาจมีการปรับปรุงอื่น ๆ ที่ไม่เกี่ยวข้องกับ WinForms ที่ควรช่วย? ที่จะตกอยู่ภายใต้กรอบ NET. ตัวเองแม้ว่าและไม่ C # โดยเฉพาะ