ฉันเพิ่งสังเกตข้อสงสัยเกี่ยวกับTask.WhenAll
วิธีการเมื่อทำงานบน. NET Core 3.0 ฉันส่งTask.Delay
งานง่าย ๆเป็นอาร์กิวเมนต์เดียวไปยังTask.WhenAll
และฉันคาดว่างานที่ถูกห่อจะทำงานเหมือนกันกับงานต้นฉบับ แต่นี่ไม่ใช่กรณี ความต่อเนื่องของงานดั้งเดิมจะถูกดำเนินการแบบอะซิงโครนัส (ซึ่งเป็นที่ต้องการ) และความต่อเนื่องของหลาย ๆ ตัวTask.WhenAll(task)
จะถูกดำเนินการแบบซิงโครนัสแบบหนึ่งหลังจากสิ่งอื่น ๆ
นี่คือตัวอย่างของพฤติกรรมนี้ งานของผู้ปฏิบัติงานสี่คนกำลังรอTask.Delay
งานเดียวกันให้เสร็จและดำเนินการคำนวณต่อไปอย่างหนัก (จำลองโดย a Thread.Sleep
)
var task = Task.Delay(500);
var workers = Enumerable.Range(1, 4).Select(async x =>
{
Console.WriteLine($"{DateTime.Now:HH:mm:ss.fff}" +
$" [{Thread.CurrentThread.ManagedThreadId}] Worker{x} before await");
await task;
//await Task.WhenAll(task);
Console.WriteLine($"{DateTime.Now:HH:mm:ss.fff}" +
$" [{Thread.CurrentThread.ManagedThreadId}] Worker{x} after await");
Thread.Sleep(1000); // Simulate some heavy CPU-bound computation
}).ToArray();
Task.WaitAll(workers);
นี่คือผลลัพธ์ การต่อเนื่องทั้งสี่แบบกำลังทำงานตามที่คาดไว้ในเธรดที่ต่างกัน (แบบขนาน)
05:23:25.511 [1] Worker1 before await
05:23:25.542 [1] Worker2 before await
05:23:25.543 [1] Worker3 before await
05:23:25.543 [1] Worker4 before await
05:23:25.610 [4] Worker1 after await
05:23:25.610 [7] Worker2 after await
05:23:25.610 [6] Worker3 after await
05:23:25.610 [5] Worker4 after await
ตอนนี้ถ้าฉันแสดงความคิดเห็นบรรทัดawait task
และ uncomment บรรทัดต่อไปนี้await Task.WhenAll(task)
เอาท์พุทค่อนข้างแตกต่าง การดำเนินการต่อทั้งหมดกำลังทำงานในเธรดเดียวกันดังนั้นการคำนวณจึงไม่ขนานกัน การคำนวณแต่ละครั้งจะเริ่มขึ้นหลังจากเสร็จสิ้นการคำนวณก่อนหน้า:
05:23:46.550 [1] Worker1 before await
05:23:46.575 [1] Worker2 before await
05:23:46.576 [1] Worker3 before await
05:23:46.576 [1] Worker4 before await
05:23:46.645 [4] Worker1 after await
05:23:47.648 [4] Worker2 after await
05:23:48.650 [4] Worker3 after await
05:23:49.651 [4] Worker4 after await
น่าประหลาดใจที่สิ่งนี้เกิดขึ้นเฉพาะเมื่อพนักงานแต่ละคนรอเสื้อคลุมที่แตกต่างกัน ถ้าฉันกำหนด wrapper upline:
var task = Task.WhenAll(Task.Delay(500));
... และจากนั้นawait
ภารกิจเดียวกันภายในพนักงานทุกคนพฤติกรรมจะเหมือนกันกับกรณีแรก
คำถามของฉันคือ:ทำไมสิ่งนี้เกิดขึ้น? อะไรทำให้ความต่อเนื่องของ wrappers ต่าง ๆ ของภารกิจเดียวกันรันในเธรดเดียวกันพร้อมกัน?
หมายเหตุ: การห่อภารกิจด้วยTask.WhenAny
แทนที่จะเป็นTask.WhenAll
ผลลัพธ์ในลักษณะการทำงานที่แปลกประหลาดเหมือนกัน
ข้อสังเกตอีกอย่าง:ฉันคาดว่าการห่อตัวเสื้อคลุมไว้ภายใน a Task.Run
จะทำให้การประสานต่อเนื่องไม่ตรงกัน แต่มันไม่ได้เกิดขึ้น ความต่อเนื่องของบรรทัดด้านล่างยังคงดำเนินการอยู่ในเธรดเดียวกัน (พร้อมกัน)
await Task.Run(async () => await Task.WhenAll(task));
ชี้แจง:ความแตกต่างดังกล่าวข้างต้นพบในแอปพลิเคชันคอนโซลที่ทำงานบนแพลตฟอร์ม. NET Core 3.0 บน. NET Framework 4.8 ไม่มีความแตกต่างระหว่างการรองานต้นฉบับหรือ wrapper งาน ในทั้งสองกรณีดำเนินการต่อเนื่องพร้อมกันในเธรดเดียวกัน
Task.WhenAll
Task.Delay
จาก100
เป็น1000
เพื่อที่จะไม่สมบูรณ์เมื่อawait
ed
await Task.WhenAll(new[] { task });
?