Mục lục
Phương thức bất đồng bộ: Phương thức sử dụng từ khóa async
- Phương thức bất đồng bộ thường trả về Task<T>, trong đó T là kiểu dữ liệu kết quả. Quy ước đặt tên phương thức kết thúc bằng Async
- Dù không có giá trị trả về, nên khai báo kiểu Task thay vì void
- Khi gọi phương thức có kiểu Task<T>, sử dụng await để nhận giá trị kiểu T
- Đặc tính lan truyền: Một phương thức chứa await phải được đánh dấu async
// Ví dụ phương thức Main bất đồng bộ
static async Task Main(string[] args)
{
string tenTep = "E:\\Temp\\a.txt";
await File.WriteAllTextAsync(tenTep, "xin chào");
string noiDung = await File.ReadAllTextAsync(tenTep);
}
Ưu tiên sử dụng phương thức bất đồng bộ khi có sẵn cả hai phiên bản đồng bộ và bất đồng bộ. Với các phương thức không hỗ trợ async, có thể dùng Wait() hoặc Result() nhưng tiềm ẩn nguy cơ deadlock.
Viết phương thức bất đồng bộ
int doDai = await LayNoiDungWebAsync("http://www.google.com", @"e:\b.txt");
Console.WriteLine(doDai);
static async Task<int> LayNoiDungWebAsync(string duongDan, string tenTep)
{
string noiDung = "";
using (HttpClient client = new HttpClient())
{
noiDung = await client.GetStringAsync(duongDan);
await File.WriteAllTextAsync(tenTep, noiDung);
}
return noiDung.Length;
}
// Sử dụng delegate bất đồng bộ trong thread pool
ThreadPool.QueueUserWorkItem(async (obj) =>
{
while (true)
{
await File.WriteAllTextAsync(@"e:\b.txt", "bbbbbbbb");
Console.WriteLine("yyyyyyyy");
}
});
Console.Read();
Lưu ý quan trọng
Trong Visual Studio 2022, ứng dụng console mặc định sử dụng .NET 6 với cú pháp top-level statement. Tính năng này cho phép viết mã trực tiếp mà không cần lớp Program hay phương thức Main.
Cách tạo phương thức Main trong .NET 6
Khi chọn tùy chọn "Không sử dụng top-level statement":
static async Task Main(string[] args)
{
int doDai = await LayNoiDungWebAsync("http://www.google.com", @"e:\b.txt");
Console.WriteLine(doDai);
}
static async Task<int> LayNoiDungWebAsync(string duongDan, string tenTep)
{
string noiDung = "";
using (HttpClient client = new HttpClient())
{
noiDung = await client.GetStringAsync(duongDan);
await File.WriteAllTextAsync(tenTep, noiDung);
}
return noiDung.Length;
}
Cơ chế chuyển đổi luồng trong async
Trong quá trình await, .NET sẽ giải phóng luồng hiện tại về thread pool và tiếp tục thực thi sau khi tác vụ hoàn thành. Có thể kiểm tra ID luồng bằng Thread.CurrentThread.ManagedThreadId:
static async Task Main(string[] args)
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
StringBuilder sb = new StringBuilder();
for(int i=0; i<5000; i++)
{
sb.Append("YYYYYYYYYYYYYYYY");
}
await File.WriteAllTextAsync(@"e:\b.txt", sb.ToString());
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
}
Phương thức bất đồng bộ trong giao diện
Từ khóa async chỉ là hướng dẫn cho trình biên dịch xử lý await, không ảnh hưởng đến cách gọi phương thức. Do đó, giao diện không thể chứa phương thức async.
Kết hợp async với yield
Từ C# 8.0 trở đi, có thể sử dụng IAsyncEnumerable cùng await foreach để xử lý luồng dữ liệu bất đồng bộ:
static async Task Main(string[] args)
{
await foreach(var giaTri in TaoDuLieu())
{
Console.WriteLine(giaTri);
}
}
static async IAsyncEnumerable<string> TaoDuLieu()
{
yield return "chào buổi sáng";
yield return "tạm biệt";
yield return "xin vui lòng";
}
ASP.NET Core và ứng dụng console không cần quan tâm đến SynchronizationContext, vì thế không cần dùng ConfigureAwait(false). Tránh trộn lẫn phương thức đồng bộ và bất đồng bộ.