async/await cơ bản
Nội dung bài · 5 mục
- 1.Khái niệm
- 2.Ví dụ
- 3.Thử ngay
- 4.Lỗi hay gặp
- 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ó
awaitbên trong phải khai báoasync. - Kiểu trả về là
Task<decimal>chứ không phảidecimal. Method không trả về gì thì dùngTask. - Theo quy ước .NET, tên method async kết thúc bằng
Async. awaitlấy ra giá trịdecimaltừ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.
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á: 5000In 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ềTkhi xong.- Method có
awaitphải làasync, trả vềTaskhoặcTask<T>. awaitchờ 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
.Resulthay.Wait()để chờ, luôn dùngawait.
Tự kiểm tra
0/3 câuMethod async không trả về giá trị nào nên khai báo kiểu trả về là gì?
async Task<string> GetNameAsync() trả về "An". Dòng nào lấy đúng chuỗi "An"?
Việc nào nên viết bằng async/await?