Khái niệm cơ bản về bất đồng bộ
Bất đồng bộ là phương pháp xử lý giúp ứng dụng không cần chờ đợi thao tác thời gian dài hoàn thành. Ví dụ:
using System.Net.Http;
using System.Threading.Tasks;
using static System.Console;
namespace Core
{
class BatDongBo
{
static void Main()
{
ThucThi();
KetThuc();
}
static void Doi()=>WriteLine("Đang chờ...");
static void KetThuc()=>WriteLine("Kết thúc...");
static int ThucThi()
{
HttpClient client = new HttpClient();
Doi();
var response = client.GetStringAsync("https://www.visualstudio.com/");
string content = response.Result;
return content.Length;
}
}
}
Trong đoạn mã này, khi gặp thao tác mạng tốn thời gian (GetStringAsync), ứng dụng bị khóa cho đến khi hoàn thành. Lập trình bất đồng bộ giải quyết vấn đề này bằng cách không yêu cầu chương trình thực thi tuần tự từ trên xuống.
Sử dụng async/await
Từ khóa async/await đơn giản hóa việc thực thi bất đồng bộ:
public async Task XuLyBatDongBo()
{
// Xử lý tác vụ...
}
Lưu ý: Phương thức đánh dấu async mà không dùng await vẫn chạy đồng bộ.
Quy tắc thiết kế phương thức bất đồng bộ
- Sử dụng
asyncđể đánh dấu phương thức - Luôn kết hợp với
awaittrong thân phương thức - Khuyến nghị dùng
Taskthay vìvoid - Đặt tên phương thức kết thúc bằng
Async - Không dùng tham số
refhoặcout
static async Task<int> TaiDuLieuAsync()
{
HttpClient client = new HttpClient();
var content = await client.GetStringAsync("https://example.com");
return content.Length;
}
Kiểu trả về của phương thức bất đồng bộ
| Loại trả về | Khi dùng await | Không dùng await |
|---|---|---|
Task<T> |
Nhận giá trị T |
Nhận đối tượng Task |
Task |
Tương đương void |
Nhận đối tượng Task |
Luồng thực thi bất đồng bộ
Quy trình hoạt động khi gặp await:
- Tạm dừng phương thức bất đồng bộ
- Trả quyền điều khiển cho phương thức gọi
- Đăng ký công việc vào luồng từ ThreadPool
- Tiếp tục xử lý sau khi tác vụ hoàn thành
static void Main()
{
var task = TaiDuLieuAsync();
Thread.Sleep(5000);
KetThuc();
}
static async Task<int> TaiDuLieuAsync()
{
WriteLine("Bắt đầu tải...");
HttpClient client = new HttpClient();
var response = client.GetStringAsync("https://example.com");
string content = await response;
return content.Length;
}
Cơ chế tác vụ (Task)
Task.Run() và Task.Run<T>() sử dụng luồng từ ThreadPool ngay lập tức, khác với await chờ đến điểm cần bất đồng bộ.
Quản lý luồng (ThreadPool)
ThreadPool tối ưu hiệu suất bằng cách tái sử dụng luồng, tránh chi phí tạo/hủy luồng liên tục.