Коли я повинен використовувати контролери Async в ASP.NET MVC?


216

У мене є проблеми з використанням асинхронних дій у ASP.NET MVC. Коли це покращує продуктивність моїх програм, а коли ні ?

  1. Чи добре використовувати асинхронні дії скрізь у ASP.NET MVC?
  2. Що стосується очікуваних методів: чи потрібно використовувати ключові слова асинхронізація / очікування, коли я хочу запитувати базу даних (через EF / NHibernate / інші ORM)?
  3. Скільки разів я можу використовувати ключові слова, що очікують, щоб асинхронно запитувати базу даних одним методом дії?

Відповіді:


109

Асинхронні методи дії корисні, коли дія повинна виконувати кілька незалежних тривалих операцій.

Типовим використанням класу AsyncController є тривалі дзвінки веб-служб.

Чи повинні виклики моєї бази даних бути асинхронними?

Пул потоків IIS часто може обробляти набагато більше запитів одночасного блокування, ніж сервер бази даних. Якщо база даних є вузьким місцем, асинхронні дзвінки не прискорять відповідь бази даних. Без механізму дроселювання, ефективне відправлення більшої роботи на переповнений сервер баз даних за допомогою асинхронних викликів просто перекладає більше навантаження на базу даних. Якщо ваша БД є вузьким місцем, асинхронні дзвінки не будуть чарівною кулею.

Ви повинні ознайомитися з 1 та 2 посиланнями

Отримано з коментарів @PanagiotisKanavos:

Більше того, асинхронізація не означає паралельну. Асинхронне виконання звільняє цінну нитку пулу від блокування зовнішнього ресурсу, не вимагаючи складності та продуктивності. Це означає, що той самий апарат IIS може обробляти більше одночасних запитів, а не те, що він буде працювати швидше.

Слід також врахувати, що блокування дзвінків починається з інтенсивного процесора. Під час стресових ситуацій блокування дзвінків призведе до збільшення затримок та переробки пулу додатків. Асинхронні дзвінки просто уникають цього


27
Що стосується асинхронізації, IIS та бази даних, публікація блогу надзвичайно стара і висновки, зроблені тут, неправильні. IIS повинен виконувати сервер набагато більше, ніж база даних, потоки нитки пулу обмежені, а довга черга запитів може призвести до 500. Все, що звільняє потік під час очікування IO, вигідно. Навіть посилання не стосуються того, про що запитувала ОП. Насправді ті ж автори написали, що ви повинні використовувати асинхронні методи БД де завгодно
Panagiotis Kanavos

30
Більше того, асинхронізація не означає паралельну. Асинхронне виконання звільняє цінну нитку пулу від блокування зовнішнього ресурсу, не вимагаючи складності та продуктивності. Це означає, що той самий апарат IIS може обробляти більше одночасних запитів, а не те, що він буде працювати швидше.
Панайотис Канавос

5
Слід також врахувати, що блокування дзвінків починається з інтенсивного процесора. Під час стресових ситуацій блокування дзвінків призведе до збільшення затримок та переробки пулу додатків. Асинхронні дзвінки просто уникають цього
Panagiotis Kanavos

1
Оскільки це прийнята відповідь і, таким чином, у верхній частині для більшості людей, може бути розумним видалити другий перший абзац щодо часу виконання та паралельного виконання, що не має нічого спільного з асинхронізацією. Я усвідомлюю, що в кінці є записка, але вона є досить оманливою.
Роб

1
Асинхронне виконання звільняє потік лише у тих випадках, коли він справді асинхронізується до самого низу реалізації та використовує якийсь механізм зворотного виклику для сигналізації про готовність та спінації нового потоку для переключення контексту та обробки результату. Отже, я не впевнений, в яких випадках це переключення контексту / створення нових потоків є більш ефективним, ніж просто очікування результатів в одному потоці? Тривалі дзвінки в Інтернет-службу в будь-якому випадку є поганою ідеєю, я вважаю за краще завантажити його на надійний фоновий сервіс і дозволити клієнту перевірити результати, які можуть з’явитися через кілька хвилин, годин або днів.
JustAMartin

229

Можливо, ви знайдете корисну мою статтю про MSDN ; У цій статті я зайняв багато місця, в якому описував, коли потрібно використовуватиasync ASP.NET, а не лише про те, як користуватися asyncASP.NET.

У мене є проблеми з використанням асинхронних дій у ASP.NET MVC. Коли це покращує продуктивність моїх програм, а коли - ні.

По-перше, зрозумійте, що async/ awaitвсе стосується звільнення тем . У програмах GUI йдеться головним чином звільнення потоку GUI, щоб зручніше було користуватися. У серверних додатках (включаючи ASP.NET MVC) мова йде, головним чином, про звільнення потоку запиту, щоб сервер міг масштабувати.

Зокрема, це не буде:

  • Зробити ваші індивідуальні запити швидше. Насправді вони завершаться (лише підлітковий шматочок) повільніше.
  • Поверніться до абонента / браузера, коли ви натиснете на await. awaitлише "поступається" пулу потоків ASP.NET, а не браузеру.

Перше питання - чи добре використовувати асинхронні дії скрізь у ASP.NET MVC?

Я б сказав, що добре використовувати його скрізь, де ви робите I / O. Це не обов'язково може принести користьОднак (див. Нижче).

Однак це погано використовувати його для методів, пов'язаних з процесором. Іноді дияволи думають, що вони можуть отримати перевагиasync , просто зателефонувавши Task.Runдо своїх контролерів, і це жахлива ідея. Оскільки цей код закінчується звільненням потоку запиту, зайнявши інший потік, тому користі взагалі немає (а насправді вони беруть штраф за додаткові комутатори потоку)!

Чи потрібно використовувати ключові слова асинхрон / очікування, коли я хочу запитувати базу даних (через EF / NHibernate / інші ORM)?

Ви можете використовувати будь-які доступні вам методи. Зараз більшість основних гравців підтримуютьasync , але є кілька таких, які цього не роблять. Якщо ваш ORM не підтримує async, то не намагайтеся завертати його Task.Runчи щось подібне (див. Вище).

Зауважте, що я сказав "ви можете використовувати". Якщо ви говорите про ASP.NET MVC з єдиним резервним бази даних, ви (майже напевно) не отримаєте користі від масштабування async. Це тому, що IIS може обробляти набагато більше одночасних запитів, ніж один екземпляр SQL-сервера (або іншого класичного RDBMS). Однак, якщо ваш сервер заходу більш сучасний - кластер SQL-сервера, Azure SQL, NoSQL тощо - і ваш бекенд може масштабуватися, а вузьке місце масштабування - IIS, то ви можете отримати користь від масштабування async.

Третє запитання - Скільки разів я можу використовувати ключові слова, що очікують, щоб асинхронно запитувати базу даних в методі ОДНОЇ єдиної дії?

Скільки вам подобається. Однак зауважте, що багато ORM мають правило "одна операція на з'єднання". Зокрема, EF дозволяє проводити лише одну операцію на кожен DbContext; це вірно, незалежно від того, чи є операція синхронною чи асинхронною.

Також знову пам’ятайте про масштабованість вашого бекенда. Якщо ви потрапляєте на один екземпляр SQL Server, а ваш IIS вже здатний підтримувати SQLServer на повну потужність, то подвоєння або зменшення тиску на SQLServer взагалі не допоможе вам.


2
@seebiscuit: При виконанні (належного асинхронного) вводу / виводу жодні потоки не використовуються. У мене є допис у блозі, який детальніше описується.
Стівен Клірі

2
Скільки запитів може обробити IIS та один екземпляр SQL Server? Як я можу знайти ці цифри?
MOD

1
@MOD: Це залежить від конфігурації та обладнання. Єдиний спосіб знайти ці цифри - це зробити перевірку завантаження на власному сервері.
Стівен Клірі

1
@Flezcano: методи, які повністю виконуються на процесорі. Тобто вони не роблять I / O або блокують.
Стівен Клірі

1
Вибачте, сер, але ТАК не хочу прийняти це питання щодо 2-х лайнерів, яке я намагаюся зрозуміти. на сервер кожного з цієї тисячі запитів або я повинен зробити його асинхронним, щоб обробити 1000 запитів?
Заучування-переосмислений-плутаний

21

чи добре використовувати асинхронні дії скрізь у ASP.NET MVC?

Як зазвичай у програмуванні, це залежить . Завжди є компроміс, коли йдеш певним шляхом.

async-awaitсвітить у місцях, де ви знаєте, що отримуєте одночасні запити до вашої служби, і ви хочете мати можливість масштабувати масштаб . Як async-awaitдопомагає зменшити масштаб? У тому випадку, що коли ви викликаєте виклик асинхронного вводу-виводу синхронно , наприклад, мережевий дзвінок або потрапляння у вашу базу даних, поточний потік, який відповідає за виконання, блокується в очікуванні завершення запиту. Коли ви використовуєтеasync-await ви дозволяєте рамці створити машину стану для вас, яка гарантує, що після завершення виклику IO ваш метод продовжує виконувати з того місця, де він припинився.

Варто зазначити, що ця державна машина має тонкі накладні витрати. Якщо зробити метод асинхронним, це не змушує його виконувати швидше , і це важливий фактор для розуміння та помилкового уявлення багатьох людей.

Ще одна річ, яку слід враховувати при використанні, async-await- це той факт, що він асинхронізований до кінця , це означає, що ви побачите, як асинхрон проникає через весь стек викликів, зверху до buttom. Це означає, що якщо ви хочете викрити синхронні API, ви часто будете дублювати певну кількість коду, оскільки асинхронізація та синхронізація не дуже добре поєднуються.

Чи потрібно використовувати ключові слова асинхрон / очікування, коли я хочу запитувати базу даних (через EF / NHibernate / інші ORM)?

Якщо ви вирішите піти по шляху використання викликів асинхронного вводу-виводу, то так, async-awaitбуде хорошим вибором, оскільки все більше сучасних постачальників баз даних розкривають метод асинхронізації, що реалізує TAP (Task Asynchronous Pattern).

Скільки разів я можу використовувати ключові слова, що очікують, щоб асинхронно запитувати базу даних в методі ОДНОЇ єдиної дії?

Скільки вам потрібно, дотримуйтесь правил, вказаних вашим постачальником даних. Обмеження кількості асинхронних дзвінків, які ви можете здійснювати, не обмежується. Якщо у вас є запити, які не залежать один від одного, і їх можна одночасно робити, ви можете розгорнути нове завдання для кожного і використовувати, await Task.WhenAllщоб чекати, коли вони завершаться.


2
Асинхронні виклики db не виконуються швидше, але дозволяють одній машині IIS подавати ще багато запитів, тому що потоки ниток пульсу не марнуються. Це також знижує витрати на процесор, оскільки блокування дзвінків насправді починається з інтенсивного процесора, а не блокування. У ситуаціях з високим навантаженням це може бути різниця між машиною, яка бореться або виходить з ладу та переробляє
Panagiotis Kanavos

@PanagiotisKanavos Я знаю, це було незрозуміло з того, що я сказав?
Ювал Ітчаков

1
Ваша відповідь не згадує специфіку IIS - сценарій перебоїв / переробки є основною причиною використання асинхронізації протягом усього часу. Хтось, хто цього не відчував, напевно, не зрозуміє, що це scale out wellможе означати your server won't die under load. Або це може бути випадокonce burned ...
Панайотис Канавос

7

Мої 5 центів:

  1. Використовуйте async/await якщо і тільки якщо ви виконуєте операцію вводу-виводу, наприклад, БД або зовнішню службову службу.
  2. Завжди віддайте перевагу асинхронним дзвінкам до БД.
  3. Кожен раз, коли ви запитуєте БД.

PS Існують виняткові випадки для пункту 1, але для цього вам потрібно добре розуміти асинхронні внутрішні системи.

В якості додаткової переваги ви можете робити кілька дзвінків IO паралельно, якщо потрібно:

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

asyncдії найкраще допомагають, коли дії виконують деякі операції вводу-виводу в БД або деякі виклики, пов’язані з мережею, де потік, який обробляє запит, буде зупинений, перш ніж він отримає відповідь від виклику, пов'язаного з БД або мережевого дзвінка, на який ви тільки що викликали. Найкраще, якщо ви використовуєте функцію очікування з ними, і це дійсно поліпшить чуйність вашої програми (адже менше вхідних / вихідних потоків ASP буде затримуватися під час очікування БД або будь-якої іншої операції подібної). У всіх моїх програмах, коли дуже багато дзвінків до БД дуже потрібні, я завжди обертав їх очікуваним методом і називав це awaitключовим словом.


5

Як відомо, MVC підтримує асинхронні контролери, і ви повинні цим скористатися. Якщо ваш Контролер виконує тривалу операцію (це може бути диск на базі диска або мережевий дзвінок до іншої віддаленої служби), якщо запит обробляється синхронно, потік IIS весь час зайнятий. В результаті нитка просто чекає завершення тривалої операції. Це може бути краще використане, подаючи інші запити, поки операція, яку вимагають спочатку, триває. Це допоможе подавати більше одночасних запитів. Ваш веб-сервіс буде масштабованим і не може легко зіткнутися з проблемою C10k . Це гарна ідея використовувати асинхронізацію / очікувати для запитів db. і так, ви можете використовувати їх стільки разів, скільки вважаєте за потрібне.

Подивіться тут на відмінну пораду.


3

Мій досвід полягає в тому, що сьогодні багато розробників використовують async/awaitдля контролерів за замовчуванням.

Моя пропозиція була б, використовуйте її лише тоді, коли знаєте, що вам це допоможе .

Причина полягає в тому, що Стівен Клірі та інші, про які вже згадувалося, вони можуть вносити проблеми з ефективністю, а не вирішувати їх, і це допоможе вам лише у конкретному сценарії:

  • Контролери з високим трафіком
  • Масштабований бекенд

2

Чи добре використовувати асинхронні дії скрізь у ASP.NET MVC?

Це добре робити там, де ви можете використовувати метод асинхронізації, особливо коли у вас є проблеми з продуктивністю на рівні робочого процесу, що відбувається для масових операцій з даними та розрахунками. В іншому випадку немає необхідності, оскільки для тестування блоків буде потрібно кастинг.

Що стосується очікуваних методів: чи потрібно використовувати ключові слова асинхронізація / очікування, коли я хочу запитувати базу даних (через EF / NHibernate / інші ORM)?

Так, краще використовувати async для будь-якої операції з БД, наскільки це можливо, щоб уникнути проблем з продуктивністю на рівні робочих процесів. Зауважте, що EF створив безліч альтернатив асинхронізації для більшості операцій, таких як:

.ToListAsync()
.FirstOrDefaultAsync()
.SaveChangesAsync()
.FindAsync()

Скільки разів я можу використовувати ключові слова, що очікують, щоб асинхронно запитувати базу даних одним методом дії?

Небо - це межа


Бізнес-логіка для більшості веб-додатків зазвичай потребує дуже послідовних операцій, тому стрибки між паралельними процесами у більшості випадків є життєздатними лише на самому верхньому рівні управління веб-запитом / робочим процесом, який так чи інакше не стосується запитів баз даних. Я дуже хотів би побачити приклади реального світу типового веб-додатку, де було б насправді гарною ідеєю обробляти запити БД асинхронним чином.
JustAMartin
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.