Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> C#

วิธีรัน Multiple Async Tasks และรอให้เสร็จทั้งหมดใน C#

ใน C# มี 2 วิธีหลักสำหรับรอหลาย Task ให้เสร็จ:

Method Behavior Return Type Blocking?
Task.WaitAll() บล็อก Thread ปัจจุบันจนกว่าทุก Task จะเสร็จ void Yes (Synchronous Block)
Task.WhenAll() คืน Task ที่เสร็จเมื่อทุก Task เสร็จ (Non-blocking) Task No (Awaitable)

ตัวอย่าง 1: Task.WhenAll (Non-blocking, แนะนำสำหรับ Async)

static async Task Main(string[] args)
{
    Task task1 = Task.Run(async () =>
    {
        for (int i = 0; i < 5; i++)
        {
            Console.WriteLine($"Task 1 - iteration {i}");
            await Task.Delay(1000);
        }
        Console.WriteLine("Task 1 complete");
    });

    Task task2 = Task.Run(async () =>
    {
        for (int i = 0; i < 5; i++)
        {
            Console.WriteLine($"Task 2 - iteration {i}");
            await Task.Delay(1000);
        }
        Console.WriteLine("Task 2 complete");
    });

    Console.WriteLine("Waiting for tasks to complete (WhenAll)...");
    await Task.WhenAll(task1, task2); // Non-blocking await
    Console.WriteLine("Both Tasks Completed.");
}

ผลลัพธ์ (ลำดับอาจสลับเพราะรัน Parallel)

Waiting for tasks to complete (WhenAll)...
Task 1 - iteration 0
Task 2 - iteration 0
Task 1 - iteration 1
Task 2 - iteration 1
...
Task 1 complete
Task 2 complete
Both Tasks Completed.

ตัวอย่าง 2: Task.WaitAll (Blocking - ใช้ใน Console App Main แบบ Sync)

static void Main(string[] args)
{
    Task task1 = Task.Run(() =>
    {
        for (int i = 0; i < 5; i++)
        {
            Console.WriteLine($"Task 1 - iteration {i}");
            Thread.Sleep(1000); // Blocking sleep
        }
        Console.WriteLine("Task 1 complete");
    });

    Task task2 = Task.Run(() =>
    {
        for (int i = 0; i < 5; i++)
        {
            Console.WriteLine($"Task 2 - iteration {i}");
            Thread.Sleep(1000);
        }
        Console.WriteLine("Task 2 complete");
    });

    Console.WriteLine("Waiting for tasks to complete (WaitAll)...");
    Task.WaitAll(task1, task2); // Blocking
    Console.WriteLine("Both Tasks Completed.");
}

ตัวเลือกอื่นๆ

  • Task.WhenAny(): รอจนกว่า ใดๆ หนึ่ง จะเสร็จ
  • Parallel.ForEach / Parallel.Invoke: สำหรับ CPU-bound work (ไม่ใช่ I/O async)
  • SemaphoreSlim: จำกัดจำนวน Concurrent Tasks (Throttling)

Best Practice

  • ใน Async Context (Controller, Service) ใช้ await Task.WhenAll()
  • ใน Entry Point แบบ Sync (Console Main) ใช้ Task.WaitAll() หรือ .GetAwaiter().GetResult()
  • หลีกเลี่ยง .Result หรือ .Wait() บน Task เดี่ยว (อาจ Deadlock)