Câu hỏi Khi nào tôi nên sử dụng bộ điều khiển Async trong ASP.NET MVC?


Tôi có một số mối quan tâm bằng cách sử dụng hành động async trong ASP.NET MVC. Khi nào nó cải thiện hiệu suất của ứng dụng của tôi và khi nào nó không phải?

  1. Là nó tốt để sử dụng hành động async ở khắp mọi nơi trong ASP.NET MVC?
  2. Về phương pháp chờ đợi: tôi có nên sử dụng từ khóa không đồng bộ / chờ đợi khi tôi muốn truy vấn cơ sở dữ liệu (qua EF / NHibernate / ORM khác) không?
  3. Tôi có thể sử dụng bao nhiêu lần để từ khóa truy vấn cơ sở dữ liệu không đồng bộ trong một phương pháp hành động đơn lẻ?

170
2018-06-01 06:21


gốc




Các câu trả lời:


Hành động không đồng bộ các phương thức rất hữu ích khi một hành động phải thực hiện một số hoạt động chạy dài độc lập.

Một cách sử dụng điển hình cho lớp AsyncController là Web dài hạn   các cuộc gọi dịch vụ.

Các cuộc gọi cơ sở dữ liệu của tôi có nên không đồng bộ không?

Hồ bơi thread IIS thường có thể xử lý nhiều yêu cầu chặn đồng thời hơn một máy chủ cơ sở dữ liệu. Nếu cơ sở dữ liệu là nút cổ chai, các cuộc gọi không đồng bộ sẽ không tăng tốc độ đáp ứng của cơ sở dữ liệu. Nếu không có một cơ chế điều tiết, hiệu quả chuyển nhiều công việc hơn đến một máy chủ cơ sở dữ liệu bị quá tải bằng cách sử dụng các cuộc gọi không đồng bộ chỉ đơn thuần là thay đổi thêm gánh nặng cho cơ sở dữ liệu. Nếu DB của bạn là nút cổ chai, các cuộc gọi không đồng bộ sẽ không phải là dấu đầu dòng ma thuật.

Bạn Nên có một cái nhìn tại 1 và 2 tài liệu tham khảo

Xuất phát từ nhận xét của @PanagiotisKanavos:

Hơn nữa, async không có nghĩa là song song. Thực thi không đồng bộ giải phóng một   chuỗi threadpool có giá trị từ chặn cho tài nguyên bên ngoài, cho   không phức tạp hoặc chi phí hiệu suất. Điều này có nghĩa là cùng một máy IIS có thể   xử lý nhiều yêu cầu đồng thời hơn, không phải là yêu cầu sẽ chạy nhanh hơn.

Bạn cũng nên xem xét việc chặn cuộc gọi bắt đầu bằng   CPU spinwait chuyên sâu. Trong thời gian căng thẳng, chặn cuộc gọi sẽ   dẫn đến sự chậm trễ và tái chế hồ bơi ứng dụng. Cuộc gọi không đồng bộ   đơn giản là tránh điều này


86
2018-06-01 06:33



Về async, IIS và cơ sở dữ liệu, bài đăng trên blog rất cũ và các kết luận được rút ra ở đây là sai. IIS có máy chủ nhiều tải lớn hơn so với cơ sở dữ liệu, threadpool đề được giới hạn và một hàng đợi yêu cầu dài có thể dẫn đến 500. Bất cứ điều gì giải phóng một thread trong khi chờ đợi cho IO là có lợi. Ngay cả các liên kết không phải về những gì OP hỏi. Trên thực tế, các tác giả đã viết rằng bạn Nên sử dụng các phương thức DB không đồng bộ ở bất cứ đâu bạn có thể - Panagiotis Kanavos
Hơn nữa, async không có nghĩa là song song. Việc thực thi không đồng bộ giải phóng một luồng threadpool có giá trị khỏi việc chặn cho một tài nguyên bên ngoài, vì không có chi phí phức tạp hoặc hiệu suất. Điều này có nghĩa là cùng một máy IIS có thể xử lý hơn yêu cầu đồng thời, không phải là yêu cầu sẽ chạy nhanh hơn. - Panagiotis Kanavos
cảm ơn bạn @PanagiotisKanavos vì đã chia sẻ ý kiến ​​của bạn. - tharif
Bạn cũng nên xem xét rằng các cuộc gọi chặn bắt đầu với một spinwait chuyên sâu CPU. Trong thời gian căng thẳng, việc chặn cuộc gọi sẽ dẫn đến sự chậm trễ và tái chế hồ bơi ứng dụng. Các cuộc gọi không đồng bộ chỉ đơn giản là tránh điều này - Panagiotis Kanavos
Vì đây là câu trả lời được chấp nhận và do đó ở đầu cho hầu hết mọi người, có thể là khôn ngoan để loại bỏ đoạn thứ nhất liên quan đến thời gian thực thi và chạy song song, không liên quan gì đến async. Tôi nhận ra có một lưu ý ở cuối, nhưng nó Là khá gây hiểu lầm. - Rob♦


Bạn có thể tìm thấy Bài viết MSDN về chủ đề hữu ích; Tôi đã mất rất nhiều không gian trong bài viết mô tả khi nào bạn nên sử dụng async trên ASP.NET, không chỉ làm sao sử dụng async trên ASP.NET.

Tôi có một số mối quan tâm bằng cách sử dụng hành động async trong ASP.NET MVC. Khi nó cải thiện hiệu suất của ứng dụng của tôi và khi nào - không.

Đầu tiên, hãy hiểu rằng async/await là tất cả về giải phóng chủ đề. Trên các ứng dụng GUI, chủ yếu là về giải phóng thread GUI để trải nghiệm người dùng tốt hơn. Trên các ứng dụng máy chủ (bao gồm ASP.NET MVC), nó chủ yếu là về giải phóng chuỗi yêu cầu để máy chủ có thể mở rộng quy mô.

Đặc biệt, nó sẽ không:

  • Làm cho các yêu cầu cá nhân của bạn hoàn thành nhanh hơn. Trong thực tế, họ sẽ hoàn thành (chỉ là một chút thiếu niên) chậm hơn.
  • Quay lại trình duyệt / người gọi khi bạn nhấn await. await chỉ "sản lượng" vào nhóm chủ đề ASP.NET, không phải cho trình duyệt.

Câu hỏi đầu tiên là - là nó tốt để sử dụng hành động async ở khắp mọi nơi trong ASP.NET MVC?

Tôi muốn nói nó là tốt để sử dụng nó ở khắp mọi nơi bạn đang làm I / O. Nó có thể không nhất thiết phải là có lợi, mặc dù (xem bên dưới).

Tuy nhiên, đó là xấu để sử dụng nó cho các phương pháp liên kết CPU. Đôi khi các nhà phát triển nghĩ rằng họ có thể nhận được lợi ích của async bằng cách gọi điện thoại Task.Run trong bộ điều khiển của họ, và đây là một ý tưởng khủng khiếp. Bởi vì mã đó kết thúc giải phóng chuỗi yêu cầu bằng cách lấy một luồng khác, vì vậy không có lợi ích nào cả (và trên thực tế, chúng đang lấy hình phạt của các công tắc chủ đề phụ)!

Tôi có nên sử dụng từ khóa không đồng bộ / chờ đợi khi tôi muốn truy vấn cơ sở dữ liệu (qua EF / NHibernate / ORM khác) không?

Bạn có thể sử dụng bất kỳ phương pháp awaitable bạn có sẵn. Ngay bây giờ hầu hết các hỗ trợ người chơi chính async, nhưng có một số ít thì không. Nếu ORM của bạn không hỗ trợ async, sau đó đừng cố bọc nó vào Task.Run hoặc bất cứ điều gì tương tự (xem ở trên).

Lưu ý rằng tôi đã nói "bạn có thể Nếu bạn đang nói về ASP.NET MVC với một cơ sở dữ liệu phụ trợ duy nhất, sau đó bạn (gần như chắc chắn) sẽ không nhận được bất kỳ lợi ích khả năng mở rộng từ async. Điều này là do IIS có thể xử lý các yêu cầu đồng thời nhiều hơn so với một cá thể máy chủ SQL (hoặc các RDBMS cổ điển khác). Tuy nhiên, nếu chương trình phụ trợ của bạn hiện đại hơn - cụm máy chủ SQL, Azure SQL, NoSQL, v.v. và chương trình phụ trợ của bạn có thể mở rộng quy mô và nút cổ chai khả năng mở rộng của bạn là IIS, sau đó bạn có thể nhận được lợi ích mở rộng từ async.

Câu hỏi thứ ba - Có bao nhiêu lần tôi có thể sử dụng từ khóa chờ đợi để truy vấn cơ sở dữ liệu không đồng bộ trong MỘT phương thức hành động đơn lẻ?

Như nhiều như bạn muốn. Tuy nhiên, lưu ý rằng nhiều ORM có quy tắc một lần cho mỗi kết nối. Đặc biệt, EF chỉ cho phép một hoạt động trên mỗi DbContext; điều này đúng cho dù hoạt động là đồng bộ hay không đồng bộ.

Ngoài ra, hãy nhớ lại khả năng mở rộng của chương trình phụ trợ của bạn. Nếu bạn đang nhấn một cá thể của SQL Server, và IIS của bạn đã có khả năng giữ SQLServer hết công suất, sau đó tăng gấp đôi hoặc gấp ba lần áp lực trên SQLServer sẽ không giúp gì cho bạn cả.


184
2018-06-01 13:16



@seebiscuit: Khi thực hiện (không đồng bộ) I / O, không có chủ đề nào được sử dụng. tôi có một bài viết trên blog mà đi vào chi tiết hơn. - Stephen Cleary
Có bao nhiêu yêu cầu có thể IIS và một cá thể SQL Server instance xử lý? Làm thế nào tôi có thể tìm thấy những con số này? - MOD
@MOD: Nó phụ thuộc vào cấu hình và phần cứng. Cách duy nhất để tìm những con số này là thực hiện kiểm tra tải trên máy chủ của riêng bạn. - Stephen Cleary
@ Flezcano: Các phương thức thực hiện đầy đủ trên CPU. Tức là, họ không làm I / O hoặc chặn. - Stephen Cleary
Xin lỗi sir nhưng SO wont chấp nhận câu hỏi này 2 lót mà tôi đang cố gắng để hiểu. Khi tôi đã nghiên cứu cho điều này như thế nếu tôi có 1 điểm api api web được gọi là bởi 1000 người sử dụng cùng một lúc thì sẽ kết thúc điểm này sẽ có thể để máy chủ mỗi nghìn yêu cầu này hoặc tôi nên làm cho nó không đồng bộ để xử lý 1000 yêu cầu? - Learning-Overthinker-Confused


là nó tốt để sử dụng hành động async ở khắp mọi nơi trong ASP.NET MVC?

Như thường lệ trong lập trình, nó phụ thuộc. Luôn luôn có một sự cân bằng khi đi xuống một con đường nhất định.

async-await tỏa sáng ở những nơi bạn biết bạn sẽ nhận được yêu cầu đồng thời cho dịch vụ của mình và bạn muốn có thể mở rộng tốt. Làm thế nào async-await giúp đỡ với quy mô ra? Trong thực tế là khi bạn gọi một cuộc gọi IO không đồng bộ đồng bộ, chẳng hạn như cuộc gọi mạng hoặc nhấn cơ sở dữ liệu của bạn, luồng hiện tại chịu trách nhiệm thực thi bị chặn chờ yêu cầu hoàn tất. Khi bạn sử dụng async-await, bạn kích hoạt khung công tác để tạo ra một máy trạng thái cho bạn, đảm bảo rằng sau khi cuộc gọi IO hoàn tất, phương thức của bạn tiếp tục thực hiện từ nơi nó đã dừng lại.

Một điều cần lưu ý là máy trạng thái này có chi phí tinh tế. Tạo phương thức không đồng bộ không làm cho nó hoạt động nhanh hơn, và đó là một yếu tố quan trọng để hiểu và một quan niệm sai lầm mà nhiều người có.

Một điều cần lưu ý khi sử dụng async-await thực tế là nó là async tất cả các cách, có nghĩa là bạn sẽ thấy async xâm nhập toàn bộ ngăn xếp cuộc gọi của bạn, từ đầu đến mông. Điều này có nghĩa là nếu bạn muốn hiển thị API đồng bộ, bạn sẽ thường thấy mình sao chép một số lượng mã nhất định, như không đồng bộ và đồng bộ hóa không pha trộn rất tốt.

Tôi sẽ sử dụng từ khóa không đồng bộ / chờ đợi khi tôi muốn truy vấn cơ sở dữ liệu (thông qua   EF / NHibernate / ORM khác)?

Nếu bạn chọn đi xuống đường dẫn sử dụng các cuộc gọi IO không đồng bộ, thì có, async-await sẽ là một lựa chọn tốt, vì ngày càng nhiều nhà cung cấp cơ sở dữ liệu hiện đại vạch trần phương thức async thực hiện TAP (Task Asynchronous Pattern).

Tôi có thể sử dụng bao lâu để truy vấn từ khóa để truy vấn cơ sở dữ liệu   không đồng bộ trong MỘT phương thức hành động đơn lẻ?

Nhiều như bạn muốn, miễn là bạn tuân theo các quy tắc được nhà cung cấp cơ sở dữ liệu của bạn nêu. Không có giới hạn số lượng cuộc gọi không đồng bộ mà bạn có thể thực hiện. Nếu bạn có các truy vấn độc lập với nhau và có thể được thực hiện đồng thời, bạn có thể quay một nhiệm vụ mới cho mỗi và sử dụng await Task.WhenAll đợi cả hai hoàn thành.


18
2018-06-01 06:38



Các cuộc gọi db không đồng bộ không thực thi nhanh hơn nhưng cho phép cùng một máy IIS để phục vụ nhiều yêu cầu hơn bởi vì các luồng threadpool không bị lãng phí. Nó cũng làm giảm chi phí CPU bởi vì chặn cuộc gọi thực sự bắt đầu với một spinwait chuyên sâu CPU trước khi thực sự chặn. Trong trường hợp tải trọng cao, đây có thể là sự khác biệt giữa máy đang gặp khó khăn hoặc thất bại và tái chế - Panagiotis Kanavos
@PanagiotisKanavos Tôi biết, có phải là không rõ ràng từ những gì tôi nói? - Yuval Itzchakov
Câu trả lời của bạn không đề cập đến các chi tiết cụ thể của IIS - kịch bản meltdown / recycle là một lý do chính để sử dụng async trong suốt. Một người không có kinh nghiệm có lẽ sẽ không hiểu rằng scale out well có thể có nghĩa là your server won't die under load. Hoặc nó có thể là một trường hợp once burned ... - Panagiotis Kanavos


async Các hành động sẽ giúp tốt nhất khi các hành động thực hiện một số hoạt động I-O tới DB hoặc một số cuộc gọi bị ràng buộc mạng trong đó luồng xử lý yêu cầu sẽ bị trì hoãn trước khi nó nhận được câu trả lời từ DB hoặc cuộc gọi bị ràng buộc mạng mà bạn vừa gọi. Tốt nhất là bạn sử dụng await với họ và nó sẽ thực sự cải thiện sự đáp ứng của ứng dụng của bạn (vì ít đầu vào ASP đầu ra \ sẽ bị trì hoãn trong khi chờ đợi cho DB hoặc bất kỳ hoạt động khác như thế). Trong tất cả các ứng dụng của tôi bất cứ khi nào nhiều cuộc gọi đến DB rất cần thiết, tôi luôn luôn bọc chúng trong phương pháp awaiatable và gọi đó với await từ khóa.


6
2018-06-01 06:28





5 xu của tôi:

  1. Sử dụng async/await nếu và chỉ khi bạn thực hiện thao tác IO, như DB hoặc dịch vụ web dịch vụ bên ngoài.
  2. Luôn thích cuộc gọi không đồng bộ với DB.
  3. Mỗi lần bạn truy vấn DB.

P.S. Có những trường hợp đặc biệt cho điểm 1, nhưng bạn cần phải có một sự hiểu biết tốt về nội bộ async cho việc này.

Là một lợi thế bổ sung, bạn có thể thực hiện một vài cuộc gọi IO song song nếu cần:

Task task1 = FooAsync(); // launch it, but don't wait for result
Task task2 = BarAsync(); // launch bar; now both foo and bar are running
await Task.WhenAll(task1, task2); // this is better in regard to exception handling
// use task1.Result, task2.Result

6
2018-06-11 21:51





Như bạn đã biết, MVC hỗ trợ các bộ điều khiển không đồng bộ và bạn nên tận dụng nó. Trong trường hợp Controller của bạn, thực hiện một hoạt động dài, (nó có thể là một đĩa dựa trên I / o hoặc một cuộc gọi mạng đến một dịch vụ từ xa khác), nếu yêu cầu được xử lý theo cách đồng bộ, thì thread IIS bận suốt thời gian. Kết quả là, luồng chỉ đang chờ thao tác dài để hoàn thành. Nó có thể được sử dụng tốt hơn bằng cách phục vụ các yêu cầu khác trong khi hoạt động yêu cầu đầu tiên đang được tiến hành. Điều này sẽ giúp phục vụ nhiều yêu cầu đồng thời hơn. Dịch vụ web của bạn sẽ có khả năng mở rộng cao và sẽ không dễ dàng chạy vào C10k vấn đề. Bạn nên sử dụng async / await cho truy vấn db. và có bạn có thể sử dụng chúng nhiều lần như bạn thấy phù hợp.

Hãy xem đây cho lời khuyên tuyệt vời.


2
2018-06-01 06:46