0
0
Lập trình
Flame Kris
Flame Krisbacodekiller

Hiểu rõ về Async Await trong lập trình C#

Đăng vào 5 tháng trước

• 4 phút đọc

Giới thiệu

Trong lập trình C#, asyncawait là hai từ khóa quan trọng giúp tạo ra các phương thức bất đồng bộ. Điều này cho phép bạn thực hiện các tác vụ mà không làm nghẽn giao diện người dùng (UI) hoặc làm chậm ứng dụng của bạn. Bài viết này sẽ đi sâu vào cách sử dụng asyncawait, cùng với các thực tiễn tốt nhất và những cạm bẫy thường gặp.

Nội dung

  1. Cách thức hoạt động của async và await
  2. Tìm hiểu về Task và Task
  3. So sánh Task.Delay và Thread.Sleep
  4. Sử dụng Task.Run để chạy tác vụ nặng
  5. Hiểu rõ Task.WhenAll và Task.WhenAny
  6. Cách sử dụng ConfigureAwait
  7. Tìm hiểu về CancellationToken
  8. Sử dụng IAsyncEnumerable
  9. Danh sách các API async phổ biến
  10. Kết luận

Cách thức hoạt động của async và await {#cach-thuc-hoat-dong}

async được sử dụng để khai báo một phương thức là bất đồng bộ. Khi bạn khai báo một phương thức với từ khóa async, điều này cho phép bạn sử dụng từ khóa await bên trong phương thức đó.

csharp Copy
public async Task RunAsync()  
{  
    Console.WriteLine("Bắt đầu");  
    await Task.Delay(2000); // 2 giây chờ, nhưng các mã khác vẫn có thể thực thi  
    Console.WriteLine("Kết thúc");  
}

Khi bạn gọi RunAsync, phương thức này sẽ bắt đầu thực thi, nhưng sau khi gặp await, nó sẽ cho phép các tác vụ khác chạy trong khi chờ đợi.

Tìm hiểu về Task và Task {#task}

  • Task là một loại đối tượng đại diện cho một tác vụ không trả về kết quả.
  • Task<TResult> là một loại đối tượng đại diện cho một tác vụ trả về một giá trị.
csharp Copy
public async Task<int> GetNumberAsync()  
{  
    await Task.Delay(1000); // mô phỏng một tác vụ mất thời gian  
    return 42;  
}

int result = await GetNumberAsync(); // result sẽ là 42

So sánh Task.Delay và Thread.Sleep {#so-sanh-taskdelay-threadsleep}

  • Task.Delay cho phép bạn chờ một khoảng thời gian mà không làm nghẽn luồng, trong khi Thread.Sleep sẽ làm nghẽn luồng.
csharp Copy
// Điều này sẽ làm UI bị đơ  
Thread.Sleep(3000);

// Điều này sẽ không làm UI bị đơ  
await Task.Delay(3000);

Sử dụng Task.Run để chạy tác vụ nặng {#taskrun}

Task.Run cho phép bạn thực hiện các tác vụ nặng trong một luồng riêng biệt.

csharp Copy
await Task.Run(() =>  
{  
    // Tính toán nặng  
    Thread.Sleep(2000);  
    Console.WriteLine("Tính toán đã hoàn tất");  
});

Hiểu rõ Task.WhenAll và Task.WhenAny {#whenall-whenany}

  • Task.WhenAll cho phép bạn chờ tất cả các tác vụ hoàn thành.
  • Task.WhenAny cho phép bạn chờ tác vụ đầu tiên hoàn thành.
csharp Copy
var t1 = Task.Delay(2000);  
var t2 = Task.Delay(3000);

await Task.WhenAll(t1, t2); // chờ cả hai tác vụ hoàn thành  
await Task.WhenAny(t1, t2); // chờ tác vụ đầu tiên hoàn thành

Cách sử dụng ConfigureAwait {#configureawait}

Khi làm việc với các ứng dụng server (ASP.NET Core) hoặc ứng dụng UI, việc chuyển đổi ngữ cảnh là rất quan trọng.

csharp Copy
await SomeTask().ConfigureAwait(false);

Điều này cho phép bạn không quay lại ngữ cảnh UI, và thường được sử dụng trong mã server.

Tìm hiểu về CancellationToken {#cancellationtoken}

CancellationToken được sử dụng để hủy bỏ một tác vụ bất đồng bộ.

csharp Copy
public async Task RunAsync(CancellationToken token)  
{  
    for (int i = 0; i < 10; i++)  
    {  
        token.ThrowIfCancellationRequested();  
        await Task.Delay(500);  
        Console.WriteLine(i);  
    }  
}

Sử dụng IAsyncEnumerable {#iasyncenumerable}

IAsyncEnumerable cho phép bạn lấy dữ liệu một cách tuần tự từ một nguồn dữ liệu lớn.

csharp Copy
public async IAsyncEnumerable<int> GetNumbersAsync()  
{  
    for (int i = 1; i <= 5; i++)  
    {  
        await Task.Delay(500);  
        yield return i;  
    }  
}

await foreach (var num in GetNumbersAsync())  
{  
    Console.WriteLine(num);  
}

Danh sách các API async phổ biến {#common-async-apis}

Dưới đây là một số API async thường được sử dụng trong C# và .NET:

  • Task.Delay – chờ một khoảng thời gian.
  • HttpClient.GetAsync – lấy dữ liệu từ internet.
  • Stream.ReadAsync / WriteAsync – làm việc với file/stream.
  • SignalR.SendAsync – gửi tin nhắn thời gian thực.
  • DbContext.SaveChangesAsync – ghi vào cơ sở dữ liệu.

Kết luận {#ket-luan}

  • Sử dụng Thread.Sleep sẽ làm nghẽn luồng và làm UI không phản hồi.
  • Sử dụng Task.Delay giúp chờ mà không làm nghẽn luồng.
  • Task.Run giúp thực hiện các tác vụ nặng trong một luồng riêng.
  • Task.WhenAllTask.WhenAny cho phép quản lý các tác vụ song song.
  • CancellationToken giúp hủy bỏ tác vụ khi cần thiết.
  • IAsyncEnumerable cho phép lấy dữ liệu tuần tự từ nguồn dữ liệu lớn.

FAQs

1. Làm thế nào để hủy bỏ một tác vụ async?
Bạn có thể sử dụng CancellationToken để hủy bỏ tác vụ khi cần thiết.

2. Sự khác biệt giữa Task và Task?
Task không trả về giá trị, trong khi Task<TResult> trả về một giá trị cụ thể.

3. Có cách nào để chạy tác vụ nặng mà không làm UI bị đơ không?
Sử dụng Task.Run để chạy tác vụ nặng trong một luồng riêng biệt mà không làm UI bị đơ.

Hy vọng bài viết này đã giúp bạn hiểu rõ hơn về cách sử dụng asyncawait trong lập trình C#. Hãy thử áp dụng những kiến thức này vào dự án của bạn nhé!

Gợi ý câu hỏi phỏng vấn
Không có dữ liệu

Không có dữ liệu

Bài viết được đề xuất
Bài viết cùng tác giả

Bình luận

Chưa có bình luận nào

Chưa có bình luận nào