Lập trình bất đồng bộ trong C# với async/await

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 await trong thân phương thức
  • Khuyến nghị dùng Task thay vì void
  • Đặt tên phương thức kết thúc bằng Async
  • Không dùng tham số ref hoặc out
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:

  1. Tạm dừng phương thức bất đồng bộ
  2. Trả quyền điều khiển cho phương thức gọi
  3. Đăng ký công việc vào luồng từ ThreadPool
  4. 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()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.

Thẻ: csharp AsyncAwait Task ThreadPool

Đăng vào ngày 16 tháng 8 lúc 10:22