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

Tasks ใน C# - Asynchronous Programming

Task คืออะไร?

Task แทนการทำงานแบบ Asynchronous (ไม่บล็อก Thread หลัก) ใน .NET ใช้สำหรับ Parallel Programming, Async/Await, และ Background Work

วิธีสร้างและเริ่ม Task

1. Task.Run() - วิธีที่ง่ายและแนะนำมากที่สุด

using System;
using System.Threading.Tasks;

public class Example {
    public static void Main() {
        // เริ่ม Task ทันที บน Thread Pool
        Task task = Task.Run(() => {
            int a = 0;
            for (a = 0; a <= 1000; a++) { }
            Console.WriteLine("{0} loop iterations ends", a);
        });
        
        task.Wait(); // รอให้ Task เสร็จ (Blocking)
        Console.WriteLine("Main thread continues...");
    }
}

2. Task Factory

// เริ่มทันที
Task.Factory.StartNew(() => {
    Console.WriteLine("Welcome from Task Factory!");
});

// หรือสร้างแล้ว Start แยก
Task task = Task.Factory.StartNew(() => DoWork());

3. Constructor + Start() (Legacy)

// ใช้ Delegate
Task t = new Task(delegate { PrintMessage(); });
t.Start();

// ใช้ Lambda
Task t = new Task(() => PrintMessage());
t.Start();

Async/Await Pattern (Modern Best Practice)

using System;
using System.Threading.Tasks;

public class AsyncDemo {
    // Async Method - คืนค่า Task
    public static async Task DownloadDataAsync(string url) {
        using (var client = new HttpClient()) {
            string result = await client.GetStringAsync(url);
            return result;
        }
    }
    
    public static async Task Main() {
        // เรียก Async Method ด้วย await
        string data = await DownloadDataAsync("https://api.example.com/data");
        Console.WriteLine(data);
        
        // รันหลาย Task พร้อมกัน (Parallel)
        var task1 = DownloadDataAsync("url1");
        var task2 = DownloadDataAsync("url2");
        var task3 = DownloadDataAsync("url3");
        
        // รอทั้งหมดเสร็จ
        string[] results = await Task.WhenAll(task1, task2, task3);
        
        // หรือรอตัวไหนตัวนึงเสร็จ
        Task first = await Task.WhenAny(task1, task2, task3);
    }
}

Task Combinators (จัดการหลาย Task)

Method คำอธิบาย
Task.WhenAll(tasks) รอให้ Task ทุกตัวเสร็จ - คืน Array ของผลลัพธ์
Task.WhenAny(tasks) รอให้ Task ตัวไหนตัวนึงเสร็จ - คืน Task ที่เสร็จก่อน
Task.WaitAll(tasks) Blocking Wait ทั้งหมด (ไม่แนะนำใน UI Thread)
Task.WaitAny(tasks) Blocking Wait ตัวไหนตัวนึง
Task.Delay(ms) สร้าง Task ที่เสร็จหลัง Delay (แทน Thread.Sleep)
Task.FromResult(value) สร้าง Task ที่เสร็จแล้วพร้อมผลลัพธ์

Task Status และ Exception Handling

Task task = Task.Run(() => {
    throw new InvalidOperationException("Error!");
});

try {
    task.Wait(); // จะโยน AggregateException
} catch (AggregateException ex) {
    foreach (var inner in ex.InnerExceptions) {
        Console.WriteLine(inner.Message);
    }
}

// หรือใช้ await (Unwrap Exception อัตโนมัติ)
try {
    await task;
} catch (InvalidOperationException ex) {
    Console.WriteLine(ex.Message); // จับได้โดยตรง
}

Task vs Thread

คุณสมบัติ Task Thread
Abstraction Level High (Work Item) Low (OS Thread)
Thread Pool ใช้ Thread Pool อัตโนมัติ สร้าง OS Thread ใหม่
Overhead ต่ำมาก สูง (1MB Stack แต่ละ Thread)
Return Value Task<T> รองรับ Result ต้องใช้ Callback/Shared State
Exception Handling AggregateException / await Unwrap Manual
Cancellation CancellationToken Built-in Manual Flag

Best Practices

  • ใช้ Task.Run() สำหรับ CPU-bound Work
  • ใช้ async/await สำหรับ I/O-bound Work
  • หลีกเลี่ยง .Result และ .Wait() (Deadlock Risk)
  • ใช้ CancellationToken สำหรับยกเลิกงาน
  • ConfigureAwait(false) ใน Library Code