Останнім часом я не можу отримати достатню кількість дивовижної картини асинхронного очікування C # 5.0. Де ти був все моє життя?
Я абсолютно в захваті від простого синтаксису, але у мене є одні невеликі труднощі. Моя проблема полягає в тому, що функції асинхронізації мають абсолютно інше оголошення від звичайних функцій. Оскільки лише інші функції асинхронізації можуть чекати на інших функціях асинхронізації, коли я намагаюся перенести якийсь старий код блокування для асинхронізації, у мене виникає ефект доміно функцій, які я повинен перетворити.
Люди називають це зараженням зомбі . Коли асинхрон покусає ваш код, він буде збільшуватися і збільшуватися. Процес перенесення не складний, це просто async
введення в декларацію та завершення повернення значення Task<>
. Але прикро це робити знову і знову під час перенесення старого синхронного коду.
Мені здається, це буде набагато природніше, якби обидва типи функцій (асинхроніка та звичайна стара синхронізація) мали абсолютно однаковий синтаксис. Якби це було так, перенесення потребує нульових зусиль, і я міг би безболісно перемикатися між двома формами.
Я думаю, що це може спрацювати, якщо ми будемо дотримуватися цих правил:
Функції асинхронізації більше не потребуватимуть
async
декларації. Їхні типи повернення не потрібно було б зафіксуватиTask<>
. Компілятор під час компіляції визначить функцію асинхронізації та автоматично виконає обгортання Завдання <>.Більше немає дзвінків із зашкодою та забуттям функцій асинхронізації. Якщо ви хочете зателефонувати у функцію асинхронізації, її потрібно буде почекати. Я навряд чи використовую вогнезахисні речі, і всі приклади шалених перегонів або тупиків завжди, здається, базуються на них. Я вважаю, що вони занадто заплутані і "не в контакті" з синхронним мисленням, яке ми намагаємося використовувати.
Якщо ви дійсно не можете жити без пожежі та забуття, для цього буде спеціальний синтаксис. У будь-якому випадку це не буде частиною простого уніфікованого синтаксису, про який я говорю.
Єдине ключове слово, яке вам потрібно для позначення асинхронного дзвінка, - це
await
. Якщо ви чекали, дзвінок асинхронний. Якщо ви цього не зробите, виклик є звичайним старим синхронним (пам’ятайте, у нас більше немає вогню та забуття).Компілятор автоматично визначить функції асинхронізації (оскільки вони вже не мають спеціальної декларації). Правило 4 робить це дуже просто - якщо функція має
await
виклик всередині, це асинхронізація.
Чи може це працювати? чи я щось пропускаю? Цей уніфікований синтаксис набагато більш текучий і може взагалі вирішити зараження зомбі.
Деякі приклади:
// assume this is an async function (has await calls inside)
int CalcRemoteBalanceAsync() { ... }
// assume this is a regular sync function (has no await calls inside)
int CalcRemoteBalance() { ... }
// now let's try all combinations and see what they do:
// this is the common synchronous case - it will block
int b1 = CalcRemoteBalance();
// this is the common asynchronous case - it will not block
int b2 = await CalcRemoteBalanceAsync();
// choosing to call an asynchronous function in a synchronous manner - it will block
// this syntax was used previously for async fire-and-forget, but now it's just synchronous
int b3 = CalcRemoteBalanceAsync();
// strange combination - it will block since it's calling a synchronous function
// it should probably show a compilation warning though
int b4 = await CalcRemoteBalance();
Примітка: це продовження цікавої пов’язаної дискусії в СО
await
негайно. Можна зробити щось на кшталт var task = FooAsync(); Bar(); await task;
. Як би я це зробив у вашій пропозиції?
async
. Я думаю, що це одна з головних переваг async
- await
: те, що дозволяє легко складати асинхронні операції (і не тільки найпростішим способом "запустити A, чекати A, запустити B, чекати B"). І вже для цього є спеціальний синтаксис: він називається await
.