VieTopik
Tiếng HànTiếng AnhIT
  • Góc học tập
Tải app
  • Thư viện
  • Luyện thi
  • Cẩm nang
  • Góc học tập
C# CoreCông cụ hằng ngày
Bài 19/19
5 phút

async/await cơ bản

Nội dung bài · 5 mục
  1. 1.Khái niệm
  2. 2.Ví dụ
  3. 3.Thử ngay
  4. 4.Lỗi hay gặp
  5. 5.Tóm tắt

Gọi API thanh toán, đọc database, tải file: những việc này mất từ vài chục mili giây tới vài giây. Trong lúc chờ, chương trình không nên đứng im. Bài này hướng dẫn cách viết code chờ việc chậm bằng async và await.

Khái niệm

📨 Task: object đại diện cho một việc đang chạy và sẽ xong sau.

Task<T> là việc sẽ trả về một giá trị kiểu T.

⏳ async/await: async đánh dấu method có chờ việc chậm bên trong, await chờ một Task xong rồi lấy kết quả mà không chặn chương trình.

Ví dụ

decimal price = await GetPriceAsync("PEN-01");
Console.WriteLine(price);   // 5000

async Task<decimal> GetPriceAsync(string code)
{
    await Task.Delay(1000);   // giả lập gọi mạng 1 giây
    return 5000m;
}
  • Method có await bên trong phải khai báo async.
  • Kiểu trả về là Task<decimal> chứ không phải decimal. Method không trả về gì thì dùng Task.
  • Theo quy ước .NET, tên method async kết thúc bằng Async.
  • await lấy ra giá trị decimal từ Task<decimal>.
  • Task.Delay(1000) chờ 1 giây mà không chặn chương trình, dùng để giả lập việc chậm.
GetPriceAsync(PEN-01) await Task.Delay(1000) trả về Task<decimal> chưa xong sau 1 giây: 5000 Console.WriteLine(price) await, chờ mà không chặn Code gọi GetPriceAsync
Thứ tự chạy của ví dụ trên

Thử ngay

Dán vào Program.cs rồi chạy dotnet run:

Console.WriteLine("1. Bắt đầu");
Task<decimal> task = GetPriceAsync("PEN-01");
Console.WriteLine("2. Đã gọi, chưa chờ");

decimal price = await task;
Console.WriteLine($"3. Giá: {price}");

async Task<decimal> GetPriceAsync(string code)
{
    Console.WriteLine("   đang tra giá...");
    await Task.Delay(500);
    Console.WriteLine("   tra xong");
    return 5000m;
}

Đoán trước khi chạy: dòng "2. Đã gọi, chưa chờ" in trước hay sau "tra xong"?

Xem kết quả
1. Bắt đầu
   đang tra giá...
2. Đã gọi, chưa chờ
   tra xong
3. Giá: 5000

In trước. Gọi GetPriceAsync thì việc tra giá bắt đầu chạy ngay, tới await Task.Delay thì quay về nơi gọi.

Chương trình in dòng 2 trong lúc việc tra giá vẫn đang chờ. Chỉ tới await task mới thật sự đứng đợi kết quả.

Lỗi hay gặp

Quên await. Không có await thì bạn nhận về Task, không phải giá trị.

// SAI — lỗi compile: Task<decimal> không phải decimal
decimal price = GetPriceAsync("PEN-01");

async Task<decimal> GetPriceAsync(string code)
{
    await Task.Delay(1000);
    return 5000m;
}
// ĐÚNG
decimal price = await GetPriceAsync("PEN-01");

Dùng .Result để lấy kết quả. .Result chặn luồng hiện tại cho tới khi có kết quả. Trong ứng dụng web, việc này làm server chậm đi, có khi treo hẳn.

// SAI — chặn luồng trong lúc chờ
decimal price = GetPriceAsync("PEN-01").Result;
// ĐÚNG — await không chặn luồng
decimal price = await GetPriceAsync("PEN-01");

Tóm tắt

  • Task<T> là việc sẽ trả về T khi xong.
  • Method có await phải là async, trả về Task hoặc Task<T>.
  • await chờ việc xong và lấy kết quả mà không chặn chương trình.
  • Tên method async kết thúc bằng Async.
  • Không dùng .Result hay .Wait() để chờ, luôn dùng await.

Tự kiểm tra

0/3 câu
Câu 1

Method async không trả về giá trị nào nên khai báo kiểu trả về là gì?

Câu 2

async Task<string> GetNameAsync() trả về "An". Dòng nào lấy đúng chuỗi "An"?

Câu 3

Việc nào nên viết bằng async/await?

Exception

Nội dung bài

  1. 1.Khái niệm
  2. 2.Ví dụ
  3. 3.Thử ngay
  4. 4.Lỗi hay gặp
  5. 5.Tóm tắt