Гаразд, ось моя думка про це.
Існує щось, що називається корутинами, про що відомо десятиліттями. ("Класс і Хоппер" -клас "десятиліттями") Вони є узагальненням підпрограм , таких як вони не тільки отримують і звільняють контроль при операції запуску і повернення функції, але і роблять це в конкретних точках ( точках припинення ). Підпрограма - це підпрограма без точок припинення.
Їх ГРУТИ ЛЕГКО реалізувати за допомогою макросів C, як показано у наступній статті про "прототрафах". ( http://dunkels.com/adam/dunkels06protothreads.pdf ) Прочитайте. Я почекаю...
Суть цього полягає в тому, що макроси створюють велику switch
та case
мітку в кожній точці підвіски. У кожній точці призупинення функція зберігає значення негайно наступногоcase
мітки, так що вона знає, де відновити виконання наступного разу, коли вона буде викликана. І це повертає контроль абоненту.
Це робиться без зміни видимого потоку управління кодом, описаного в "прототраді".
Уявіть собі, що у вас є великий цикл, що викликає по черзі всі ці "прототони", і ви одночасно виконуєте "прототради" на одному потоці.
Цей підхід має два недоліки:
- Ви не можете зберігати стан у локальних змінних між відновленнями.
- Ви не можете призупинити "прототрейд" з довільної глибини виклику. (усі точки підвіски повинні бути на рівні 0)
Для обох є вирішення:
- Усі локальні змінні повинні бути підтягнуті до контексту прототрадування (контекст, який вже потрібен тому, що прототрафа повинна зберігати свою наступну точку відновлення)
- Якщо ви відчуваєте, що вам дійсно потрібно зателефонувати ще з прототрафа, "нерестуйте" прототипу дитини та призупиніть до завершення роботи дитини.
І якби у вас була підтримка компілятора, щоб виконати роботу з перезапису, яку виконують макроси та обхідний шлях, ви можете просто написати свій код протокредиту так, як ви плануєте, і вставити пункти призупинення з ключовим словом.
А це що async
іawait
: створення (без стоп) розслідувань.
Співпраці в C # переробляються як об'єкти (загального або негенеричного) класу Task
.
Я вважаю ці ключові слова дуже оманливими. Моє розумове читання:
async
як "підвісний"
await
як "призупинити до завершення"
Task
як "майбутнє ..."
Тепер. Чи дійсно нам потрібно позначити функцію async
? Крім того, що він повинен запускати механізми перезапису коду, щоб перетворити функцію на супровід, він вирішує деякі неясності. Розглянемо цей код.
public Task<object> AmIACoroutine() {
var tcs = new TaskCompletionSource<object>();
return tcs.Task;
}
Якщо припустити, що async
це не є обов'язковим, це поправка чи нормальна функція? Чи повинен перекладач переписати його як супровід чи ні? І те й інше може бути можливим з різною можливою семантикою.