Fire-and-forget trong C#: try-catch va tam quan trong cua await

Cac phuong thuc async void doi khi duoc dung cho mo hinh fire-and-forget, tuc la goi mot tac vu bat dong bo ma khong cho ket qua tra ve. Chung cung thuong xuat hien trong cac bo xu ly su kien cua ung dung Windows Forms hoac WPF.

Hay xem doan ma C# sau:

async Task Main()
{
    try
    {
        Operations.TidyCache("");
        Console.WriteLine("Completed Successfully");
    }
    catch (Exception ex)
    {
        Console.Error.WriteLine($"Critical error: {ex.Message}");
    }
}

public static class Operations
{
    public static async void TidyCache(string key)
    {
        ArgumentException.ThrowIfNullOrEmpty(key);

        await Task.Run(async () =>
        {
            await Task.Delay(500);
            Console.WriteLine("Finished running async task : waited half a second above");
        });
    }
}

Ket qua co the la:

Completed Successfully
ArgumentException (...)
  The value cannot be an empty string. (Parameter 'key')

Van de nam o cho ta truyen mot chuoi rong vao tham so key cua phuong thuc TidyCache, nhung khoi try-catch ben ngoai lai khong bat duoc ArgumentException.

Khi mot phuong thuc async void duoc goi, no co the chay den diem await roi tra quyen dieu khien ve cho ben goi. Phan con lai cua phuong thuc duoc quan ly boi may trang thai bat dong bo. Vi phuong thuc khong tra ve mot Task, ben goi khong the await no va cung khong co cach truc tiep de quan ly loi tu tac vu do.

Trong truong hop nay, ngoai le co the vuot ra ngoai pham vi try-catch, duoc dua len thread pool va trong mot so ung dung co the dan den viec ung dung bi dung dot ngot.

Giai phap thu nhat: xu ly loi ben trong tac vu fire-and-forget

Neu that su can dung mo hinh fire-and-forget, hay de phuong thuc tra ve Task thay vi void, sau do tu xu ly loi ben trong phuong thuc. Ben goi co the dung phep gan bo qua ket qua _ =:

async Task Main()
{
    try
    {
        _ = Operations.TidyCache("");
        Console.WriteLine("Completed Successfully");
    }
    catch (Exception ex)
    {
        Console.Error.WriteLine($"Critical error: {ex.Message}");
    }
}

public static class Operations
{
    public static async Task TidyCache(string key)
    {
        try
        {
            ArgumentException.ThrowIfNullOrEmpty(key);
            await Task.Delay(500);
            Console.WriteLine("Finished running async task");
        }
        catch (Exception ex)
        {
            Console.Error.WriteLine($"TidyCache failed: {ex.Message}");
        }
    }
}

Ket qua:

TidyCache failed: The value cannot be an empty string. (Parameter 'key')
Completed Successfully

Trong cach nay, tac vu tu xu ly ngoai le cua no. Ben goi khong cho tac vu hoan tat va van tiep tuc thuc hien cac lenh tiep theo. Day la mot mau phu hop hon cho fire-and-forget, nhung can dam bao rang viec ghi log hoac xu ly loi ben trong tac vu da day du.

Giai phap thu hai: tra loi ve ben goi bang await

Trong phan lon truong hop, cach nen dung la de phuong thuc tra ve Task va await no tai noi goi. Nhu vay, ngoai le co the di theo luong thuc thi tro lai ben goi va duoc xu ly boi try-catch:

async Task Main()
{
    try
    {
        await Operations.TidyCache("");
        Console.WriteLine("Completed Successfully");
    }
    catch (Exception ex)
    {
        Console.Error.WriteLine($"Critical error: {ex.Message}");
    }
}

public static class Operations
{
    public static async Task TidyCache(string key)
    {
        ArgumentException.ThrowIfNullOrEmpty(key);

        await Task.Run(async () =>
        {
            await Task.Delay(500);
            Console.WriteLine("Finished running async task : waited half a second above");
        });
    }
}

Ket qua:

Critical error: The value cannot be an empty string. (Parameter 'key')

Day la luong xu ly ma phan lon lap trinh vien mong doi: phuong thuc bat dong bo nem ngoai le, ben goi cho phuong thuc hoan tat bang await, sau do khoi catch bat duoc ngoai le.

Ket luan

  • Han che su dung async void. Ngoai le tu phuong thuc nay khong the duoc ben goi xu ly theo cach thong thuong.
  • Chi nen dung async void cho cac bo xu ly su kien khi framework yeu cau kieu tra ve nay.
  • Voi tac vu bat dong bo thong thuong, hay dung async Task va await.
  • Neu can fire-and-forget, hay xu ly ngoai le ben trong tac vu va bao dam tac vu co co che ghi log phu hop.

Co the tom tat canh bao ve async void bang mot vai cau noi vui:

  • async void la noi ngoai le di den de chet.
  • async void la bong ma cua Task, luon am anh thoi gian chay.
  • Neu ban nghi minh can async void, co le ban can xem lai thiet ke.
  • async void giong fire-and-forget, chi khac la ban con quen ca ngon lua.
  • Hay dung async void neu ban muon ngoai le vuot qua try-catch nhu mot khach VIP.