Tôi không hiểu sự khác biệt giữa Task.Wait
và await
.
Tôi có một cái gì đó tương tự như các chức năng sau trong dịch vụ ASP.NET WebAPI:
public class TestController : ApiController
{
public static async Task<string> Foo()
{
await Task.Delay(1).ConfigureAwait(false);
return "";
}
public async static Task<string> Bar()
{
return await Foo();
}
public async static Task<string> Ros()
{
return await Bar();
}
// GET api/test
public IEnumerable<string> Get()
{
Task.WaitAll(Enumerable.Range(0, 10).Select(x => Ros()).ToArray());
return new string[] { "value1", "value2" }; // This will never execute
}
}
Nơi nào Get
sẽ bế tắc.
Điều gì có thể gây ra điều này? Tại sao điều này không gây ra vấn đề khi tôi sử dụng chờ đợi chứ không phải là await Task.Delay
?
Task.Delay(1).Wait()
về cơ bản là điều tương tự như Thread.Sleep(1000)
. Trong mã sản xuất thực tế, nó hiếm khi thích hợp.
WaitAll
đang gây ra bế tắc. Xem liên kết đến blog của tôi trong câu trả lời của tôi để biết thêm chi tiết. Bạn nên sử dụng await Task.WhenAll
thay thế.
ConfigureAwait(false)
một đơn cuộc gọi đến Bar
hoặc Ros
sẽ không bế tắc, nhưng vì bạn có một đếm được rằng đang tạo ra nhiều hơn một và sau đó chờ đợi trên tất cả các, thanh đầu tiên sẽ bế tắc thứ hai. Nếu bạn await Task.WhenAll
thay vì chờ đợi trên tất cả các nhiệm vụ, để bạn không chặn bối cảnh ASP, bạn sẽ thấy phương thức trở lại bình thường.
.ConfigureAwait(false)
tất cả các con đường lên cây cho đến khi bạn chặn, như vậy không có gì là bao giờ cố gắng để lấy lại với bối cảnh chính; rằng sẽ làm việc. Một lựa chọn khác là quay lên một bối cảnh đồng bộ hóa bên trong. Liên kết . Nếu bạn đặt nó vào, nó sẽ chặn tất cả mọi thứ Task.WhenAll
một AsyncPump.Run
cách hiệu quả mà không cần bạn phải ở ConfigureAwait
bất cứ đâu, nhưng đó có lẽ là một giải pháp quá phức tạp.
Task.Delay(1).Wait()
nó là đủ tốt.