C# - C Sharp: Toán tử await - Chờ đợi không đồng bộ để hoàn thành một tác vụ
Toán tử await
tạm dừng đánh giá phương thức async kèm theo cho đến khi thao tác không đồng bộ được biểu thị bằng toán hạng của nó hoàn tất. Khi thao tác không đồng bộ hoàn tất, toán tử await
trả về kết quả của thao tác, nếu có. Khi toán tử await
được áp dụng cho toán hạng đại diện cho một thao tác đã hoàn thành, nó sẽ trả về kết quả của thao tác ngay lập tức mà không cần tạm dừng phương thức kèm theo. Toán tử await
không chặn chuỗi đánh giá phương thức không đồng bộ. Khi toán tử await
tạm dừng phương thức async kèm theo, thì điều khiển sẽ trả về trình gọi phương thức.
Trong ví dụ sau, phương thức HttpClient.GetByteArrayAsync trả về thể hiện Task<byte[]>
, đại diện cho một thao tác không đồng bộ tạo ra một mảng byte khi nó hoàn thành. Cho đến khi thao tác hoàn tất, toán tử await
sẽ tạm dừng phương thức DownloadDocsMainPageAsync
. Khi DownloadDocsMainPageAsync
bị treo, điều khiển được trả về phương thức Main
, là trình gọi của DownloadDocsMainPageAsync
. Phương thức Main
thực thi cho đến khi nó cần kết quả của hoạt động không đồng bộ được thực hiện bởi phương thức DownloadDocsMainPageAsync
. Khi GetByteArrayAsync nhận được tất cả các byte, phần còn lại của phương thức DownloadDocsMainPageAsync
sẽ được đánh giá. Sau đó, phần còn lại của phương thức Main
được đánh giá.
using System; using System.Net.Http; using System.Threading.Tasks; public class AwaitOperator { public static async Task Main() { Task<int> downloading = DownloadDocsMainPageAsync(); Console.WriteLine($"{nameof(Main)}: Launched downloading."); int bytesLoaded = await downloading; Console.WriteLine($"{nameof(Main)}: Downloaded {bytesLoaded} bytes."); } private static async Task<int> DownloadDocsMainPageAsync() { Console.WriteLine($"{nameof(DownloadDocsMainPageAsync)}: About to start downloading."); var client = new HttpClient(); byte[] content = await client.GetByteArrayAsync("https://docs.microsoft.com/en-us/"); Console.WriteLine($"{nameof(DownloadDocsMainPageAsync)}: Finished downloading."); return content.Length; } } // Output sẽ có dạng sau: // DownloadDocsMainPageAsync: About to start downloading. // Main: Launched downloading. // DownloadDocsMainPageAsync: Finished downloading. // Main: Downloaded 27700 bytes.
Lưu ý
Để biết phần giới thiệu về lập trình không đồng bộ, hãy xem Lập trình không đồng bộ với async và await . Lập trình không đồng bộ với asyncvà awaittuân theo mẫu không đồng bộ dựa trên nhiệm vụ .
Bạn chỉ có thể sử dụng toán tử await
trong một phương thức, biểu thức lambda hoặc phương thức ẩn danh được sửa đổi bởi từ khóa async. Trong phương thức không đồng bộ, bạn không thể sử dụng toán tử await
trong phần thân của hàm đồng bộ, bên trong khối của câu lệnh khóa và trong ngữ cảnh không an toàn.
Toán hạng của toán tử await
thường thuộc một trong các loại .NET sau: Task, Task<TResult>, ValueTask hoặc ValueTask<TResult>. Tuy nhiên, bất kỳ biểu thức chờ đợi nào cũng có thể là toán hạng của toán tử await
.
Loại biểu thức await t
là TResult
nếu loại biểu thức t
là Task<TResult> hoặc ValueTask<TResult>. Nếu loại t
là Task hoặc ValueTask thì loại await t
là void
. Trong cả hai trường hợp, nếu t
ném ngoại lệ, thì await t
ném lại ngoại lệ.
Luồng không đồng bộ và lần dùng một lần
Bạn sử dụng câu lệnh await foreach
để sử dụng luồng dữ liệu không đồng bộ. Để biết thêm thông tin, hãy xem phần Câu lệnh foreach.
Bạn sử dụng câu lệnh await using
để làm việc với một đối tượng dùng một lần không đồng bộ, nghĩa là một đối tượng thuộc loại triển khai giao diện IAsyncDisposable.
Toán tử await trong phương thức Main
Phương thức Main
, là điểm vào của ứng dụng, có thể trả về Task
hoặc Task<int>
, cho phép nó không đồng bộ để bạn có thể sử dụng toán tử await
trong phần thân của nó. Trong các phiên bản C# cũ hơn, để đảm bảo rằng phương thức Main
chờ hoàn thành thao tác không đồng bộ, bạn có thể truy xuất giá trị của thuộc tính Task<TResult>.Result của thể hiện Task<TResult> được trả về bởi phương thức không đồng bộ tương ứng. Đối với các hoạt động không đồng bộ không tạo ra giá trị, bạn có thể gọi phương thức Task.Wait.