Câu trả lời:
Thực hành tốt nhất là chỉ đánh dấu chức năng async void
nếu nó là phương thức cháy và quên, nếu bạn muốn chờ đợi, bạn nên đánh dấu nó là async Task
.
Trong trường hợp nếu bạn vẫn muốn chờ đợi, thì hãy bọc nó như vậy await Task.Run(() => blah())
await Task.Run(() => An_async_void_method_I_can_not_modify_now())
await Task.Run(() => blah())
là sai lệch. Điều này không chờ đợi hoàn thành chức năng async blah
, nó chỉ chờ việc tạo (tầm thường) của tác vụ và tiếp tục ngay lập tức trước khi blah()
hoàn thành.
Thread.Sleep
không đồng bộ. Câu hỏi này là về việc chờ đợi một async void
chức năng, nóiasync void blah() { Task.Delay(10000); }
Giải pháp tốt nhất là sử dụng async Task
. Bạn nên tránh async void
vì một số lý do, một trong số đó là khả năng kết hợp.
Nếu phương thức không thể được thực hiện để trả về Task
(ví dụ: đó là một trình xử lý sự kiện), thì bạn có thể sử dụng SemaphoreSlim
để có tín hiệu phương thức khi nó sắp thoát. Xem xét làm điều này trong một finally
khối.
thực hiện AutoResetEvent, gọi hàm sau đó đợi AutoResetEvent và sau đó đặt nó vào khoảng trống async khi bạn biết nó đã hoàn thành.
Bạn cũng có thể đợi một Tác vụ trả về từ async void của bạn
Bạn không thực sự cần phải làm bất cứ điều gì bằng tay, await
từ khóa tạm dừng thực thi chức năng cho đến khi blah()
trả về.
private async void SomeFunction()
{
var x = await LoadBlahBlah(); <- Function is not paused
//rest of the code get's executed even if LoadBlahBlah() is still executing
}
private async Task<T> LoadBlahBlah()
{
await DoStuff(); <- function is paused
await DoMoreStuff();
}
T
là loại đối tượng blah()
trả về
Bạn thực sự không thể await
là một void
chức năng nên LoadBlahBlah()
không thểvoid
LoadBlahBlah()
kết thúc, không phảiblah()
Tôi biết đây là một câu hỏi cũ, nhưng đây vẫn là một vấn đề tôi tiếp tục gặp phải, nhưng vẫn chưa có giải pháp rõ ràng nào để thực hiện chính xác khi sử dụng async / await trong phương thức chữ ký async void.
Tuy nhiên, tôi nhận thấy rằng .Wait () đang hoạt động đúng trong phương thức void.
và vì async void và void có cùng chữ ký, bạn có thể cần phải làm như sau.
void LoadBlahBlah()
{
blah().Wait(); //this blocks
}
Một cách khó hiểu là async / await không chặn mã tiếp theo.
async void LoadBlahBlah()
{
await blah(); //this does not block
}
Khi bạn dịch ngược mã của mình, tôi đoán là async void tạo ra một Tác vụ bên trong (giống như Tác vụ không đồng bộ), nhưng vì chữ ký không hỗ trợ để trả về Nhiệm vụ bên trong đó
điều này có nghĩa là bên trong phương thức void async vẫn có thể "chờ" các phương thức async bên trong. nhưng bên ngoài không thể biết khi nào Nhiệm vụ nội bộ hoàn thành.
Vì vậy, kết luận của tôi là khoảng trống async hoạt động như dự định và nếu bạn cần phản hồi từ Tác vụ nội bộ, thì bạn cần sử dụng chữ ký Tác vụ async thay thế.
hy vọng lan man của tôi có ý nghĩa với bất cứ ai cũng đang tìm kiếm câu trả lời.
Chỉnh sửa: Tôi đã tạo một số mã ví dụ và dịch ngược nó để xem những gì đang thực sự xảy ra.
static async void Test()
{
await Task.Delay(5000);
}
static async Task TestAsync()
{
await Task.Delay(5000);
}
Biến thành (chỉnh sửa: Tôi biết rằng mã cơ thể không có ở đây mà là ở các stHRachines, nhưng về cơ bản thì các stHRachines giống hệt nhau, vì vậy tôi không bận tâm thêm chúng)
private static void Test()
{
<Test>d__1 stateMachine = new <Test>d__1();
stateMachine.<>t__builder = AsyncVoidMethodBuilder.Create();
stateMachine.<>1__state = -1;
AsyncVoidMethodBuilder <>t__builder = stateMachine.<>t__builder;
<>t__builder.Start(ref stateMachine);
}
private static Task TestAsync()
{
<TestAsync>d__2 stateMachine = new <TestAsync>d__2();
stateMachine.<>t__builder = AsyncTaskMethodBuilder.Create();
stateMachine.<>1__state = -1;
AsyncTaskMethodBuilder <>t__builder = stateMachine.<>t__builder;
<>t__builder.Start(ref stateMachine);
return stateMachine.<>t__builder.Task;
}
cả AsyncVoidMethodBuilder hoặc AsyncTaskMethodBuilder thực sự không có bất kỳ mã nào trong phương thức Start sẽ gợi ý chúng để chặn và sẽ luôn chạy không đồng bộ sau khi chúng được khởi động.
nghĩa là không có Nhiệm vụ trở lại, sẽ không có cách nào để kiểm tra nếu nó hoàn thành.
như mong đợi, nó chỉ khởi động Tác vụ chạy không đồng bộ, và sau đó nó tiếp tục trong mã. và tác vụ không đồng bộ, đầu tiên, nó khởi động tác vụ và sau đó nó trả về nó.
Vì vậy, tôi đoán câu trả lời của tôi sẽ là không bao giờ sử dụng async void, nếu bạn cần biết khi nào nhiệm vụ được thực hiện, đó là nhiệm vụ async dành cho.