Sử dụng Async và Await trong C#

Trong lập trình hiện đại, việc xử lý các tác vụ bất đồng bộ là một yêu cầu thiết yếu để đảm bảo hiệu suất ứng dụng. C# cung cấp hai từ khóa quan trọng là async và await để đơn giản hóa quá trình lập trình bất đồng bộ.

Ví dụ minh họa cơ bản

Dưới đây là một đoạn mã mẫu thể hiện cách sử dụng các từ khóa này:

// Quan trọng: async và await luôn đi kèm với nhau
private async void kiemTraDuLieu()
{
    int giaTri = 1;
    // Tạo luồng nền thông minh - nếu vượt quá giới hạn luồng tối đa, hệ thống sẽ đợi
    await new ChoLuongNen();
    giaTri = 2;  // Gán giá trị trong luồng không phải chính, tránh thao tác UI trực tiếp
    // Trở lại luồng chính - cần kiểm tra lại cú pháp này
    await new ChoCapNhat(); 
    Debug.Log(giaTri);
}

Ứng dụng thực tế trong kết nối mạng

Dưới đây là ví dụ về việc sử dụng bất đồng bộ trong kết nối máy tính qua mạng LAN:

private async void khoiTaoHeThong()
{
    await new ChoCuoiKhung();
    var thongTinMay = GameApp.thongTin;

    if (await HeThongTroGiup.KetNoiMayTinh("\\\\" + thongTinMay.diaChiIP, thongTinMay.taiKhoan, thongTinMay.matKhau))
    {
        if (!GameApp.Instance)
            return;
        await new ChoCapNhat();

        var duongDanMang = "\\\\" + thongTinMay.diaChiIP + @"\" + thongTinMay.tenThuMuc;
        
    }
}

/// <summary>
/// Thiết lập kết nối thư mục chia sẻ từ xa
/// </summary>
/// <param name="duongDan">Đường dẫn thư mục chia sẻ</param>
/// <param name="tenDangNhap">Tên người dùng</param>
/// <param name="matKhau">Mật khẩu truy cập</param>
/// <returns>Trạng thái kết nối thành công hay thất bại</returns>
public static async Task<bool> KetNoiMayTinh(string duongDan, string tenDangNhap, string matKhau)
{
    bool ketQua = false;
    Process tienTrinh = new Process();
    await Task.Run(() =>
    {
        try
        {
            tienTrinh.StartInfo.FileName = "cmd.exe";
            tienTrinh.StartInfo.UseShellExecute = false;
            tienTrinh.StartInfo.RedirectStandardInput = true;
            tienTrinh.StartInfo.RedirectStandardOutput = true;
            tienTrinh.StartInfo.RedirectStandardError = true;
            tienTrinh.StartInfo.CreateNoWindow = true;
            tienTrinh.Start();
            string lenh = "net use " + duongDan + " " + matKhau + " /user:" + tenDangNhap;
            tienTrinh.StandardInput.WriteLine(lenh);
            tienTrinh.StandardInput.WriteLine("exit");
            while (!tienTrinh.HasExited)
            {
                tienTrinh.WaitForExit(1000);
            }
            string loi = tienTrinh.StandardError.ReadToEnd();
            tienTrinh.StandardError.Close();
            if (string.IsNullOrEmpty(loi))
            {
                ketQua = true;
            }
            else
            {
                throw new Exception(loi);
            }
        }
        catch (Exception ex)
        {
            UnityEngine.Debug.LogError(ex.Message);
        }
        finally
        {
            tienTrinh.Close();
            tienTrinh.Dispose();
        }
    });

    return ketQua;
}

Nguyên tắc hoạt động của Async/Await

Các từ khóa async và await được giới thiệu trong C# 5.0 nhằm đơn giản hóa lập trình bất đồng bộ. Khi xử lý các tác vụ kéo dài như đọc file lớn, gọi API mạng hoặc truy vấn cơ sở dữ liệu, việc sử dụng phương pháp đồng bộ sẽ làm ứng dụng bị treo chờ cho đến khi hoàn tất.

Bằng cách áp dụng bất đồng bộ, ứng dụng có thể tiếp tục thực hiện các công việc khác không phụ thuộc vào tác vụ đang chờ, giúp cải thiện trải nghiệm người dùng đặc biệt trong các ứng dụng giao diện.

Các ví dụ thực hành

Ví dụ đầu tiên: Các phương thức độc lập

class ChayThu
{  
    static void Main(string[] args)
    {  
        PhuongThucMot();
        PhuongThucHai();
        Console.ReadKey();
    }  
  
    public static async Task PhuongThucMot()
    {  
        await Task.Run(() =>
        {  
            for (int dem = 0; dem < 100; dem++)
            {  
                Console.WriteLine(" Phuong thuc mot");  
            }  
        });  
    }  
  
    public static void PhuongThucHai()
    {  
        for (int dem = 0; dem < 25; dem++)
        {  
            Console.WriteLine(" Phuong thuc hai");  
        }  
    }  
}

Ví dụ thứ hai: Phụ thuộc giữa các phương thức

class ChayThu
{  
    static void Main(string[] args)
    {  
        GoiPhuongThuc();
        Console.ReadKey();
    }  
  
    public static async void GoiPhuongThuc()
    {  
        Task<int> nhiemVu = PhuongThucMot();
        PhuongThucHai();
        int soLuong = await nhiemVu;
        PhuongThucBa(soLuong);
    }  
  
    public static async Task<int> PhuongThucMot()
    {  
        int demSo = 0;
        await Task.Run(() =>
        {  
            for (int i = 0; i < 100; i++)
            {  
                Console.WriteLine(" Phuong thuc mot");  
                demSo += 1;
            }  
        });  
        return demSo;
    }  
  
    public static void PhuongThucHai()
    {  
        for (int i = 0; i < 25; i++)
        {  
            Console.WriteLine(" Phuong thuc hai");  
        }  
    }  
  
    public static void PhuongThucBa(int giaTri)
    {  
        Console.WriteLine("Tong so la " + giaTri);
    }  
}

Ví dụ thứ ba: Đọc file bất đồng bộ

class ChayThu
{  
    static void Main()
    {  
        Task nhiemVu = new Task(ThucHienChucNang);
        nhiemVu.Start();
        nhiemVu.Wait();
        Console.ReadLine();
    }  
  
    static async void ThucHienChucNang()
    {  
        string duongDan = "E:\\fileMau.txt";  
        Task<int> nhiemVuDoc = DocFile(duongDan);
  
        Console.WriteLine(" Cong viec khac 1");  
        Console.WriteLine(" Cong viec khac 2");  
        Console.WriteLine(" Cong viec khac 3");  
  
        int doDai = await nhiemVuDoc;
        Console.WriteLine(" Tong do dai: " + doDai);
  
        Console.WriteLine(" Sau khi xu ly 1");  
        Console.WriteLine(" Sau khi xu ly 2");  
    }  
  
    static async Task<int> DocFile(string duongDanFile)
    {  
        int doDai = 0;
  
        Console.WriteLine(" Bat dau doc file");  
        using (StreamReader docGia = new StreamReader(duongDanFile))
        {  
            string noiDung = await docGia.ReadToEndAsync();
            doDai = noiDung.Length;
        }  
        Console.WriteLine(" Ket thuc doc file");  
        return doDai;
    }  
}

Lưu ý quan trọng

Một điểm cần lưu ý là nếu không sử dụng từ khóa await, phương thức sẽ hoạt động như một phương thức đồng bộ bình thường. Trình biên dịch sẽ cảnh báo nhưng không phát sinh lỗi. Việc hiểu rõ và sử dụng đúng các từ khóa này giúp xây dựng các ứng dụng hiệu quả, phản hồi nhanh chóng với người dùng.

Thẻ: csharp async-await multithreading asynchronous-programming task-parallel-library

Đăng vào ngày 1 tháng 6 lúc 10:14