Я только начал играть с async / await в .Net 4.5. Изначально мне интересно узнать, почему необходимо ключевое слово async? Я прочитал объяснение, что это маркер, поэтому компилятор знает, что метод чего-то ждет. Но кажется, что компилятор должен быть в состоянии понять это без ключевого слова. Так что еще это делает?
19
Ответы:
Здесь есть несколько ответов, и все они говорят о том, что делают асинхронные методы, но ни один из них не отвечает на вопрос, поэтому
async
он необходим в качестве ключевого слова, которое входит в объявление функции.Это не «указание компилятору преобразовывать функцию особым образом»;
await
один мог сделать это. Почему? Поскольку C # уже имеет другой механизм , где наличие специального ключевого слова в теле метода заставляет компилятор выполнить экстремум (и очень похож наasync/await
) преобразования на теле метода:yield
.За исключением того, что
yield
это не его собственное ключевое слово в C #, и понимание, почему объяснитasync
также. В отличие от большинства языков, которые поддерживают этот механизм, в C # вы не можете сказать, чтоyield value;
вы должны сказатьyield return value;
вместо этого. Почему? Потому что он был добавлен в язык после того, как C # уже существовал, и было вполне разумно предположить, что кто-то где-то мог использоватьyield
в качестве имени переменной. Но поскольку ранее существовавшего сценария, в котором<variable name> return
синтаксически правильно не было,yield return
был добавлен язык, позволяющий вводить генераторы при сохранении 100% обратной совместимости с существующим кодом.И именно поэтому
async
был добавлен в качестве модификатора функции: чтобы не нарушать существующий код, который используетсяawait
в качестве имени переменной. Поскольку никакиеasync
методы уже не существовали, ни один старый код не был признан недействительным, и в новом коде компилятор может использовать наличиеasync
тега, чтобы знать, что егоawait
следует рассматривать как ключевое слово, а не как идентификатор.источник
async
ключевого слова может быть отменено? Очевидно, что это будет разрыв BC, но можно подумать, что он затронет очень мало проектов и будет простым требованием к обновлению (то есть изменению имени переменной).он меняет метод с обычного метода на объект с обратным вызовом, который требует совершенно другого подхода для генерации кода
и когда происходит что-то радикальное, обычно это ясно обозначают (мы извлекли урок из C ++)
источник
async
секунд одновременно, чтобы они не запускались один за другим, но одновременно (если потоки доступны по крайней мере)Task<T>
самом деле имеет характеристикиasync
метода - например, вы могли бы просто пройти через некоторую бизнес / фабричную логику и затем делегировать другому возвращающемуся методуTask<T>
.async
методы имеют тип возвратаTask<T>
в сигнатуре, но на самом деле не возвращают aTask<T>
, они просто возвращают aT
. Чтобы понять все это безasync
ключевого слова, компилятор C # должен будет выполнить всестороннюю глубокую проверку метода, что, вероятно, значительно замедлит его и приведет к всевозможным неоднозначностям.Вся идея с такими ключевыми словами, как «асинхронный» или «небезопасный», состоит в том, чтобы устранить неоднозначность относительно того, как должен обрабатываться код, который они модифицируют. В случае ключевого слова async он указывает компилятору обрабатывать модифицированный метод как нечто, что не нужно возвращать немедленно. Это позволяет потоку, в котором используется этот метод, продолжать работу, не дожидаясь результатов этого метода. Это фактически оптимизация кода.
источник
Хорошо, вот мой взгляд на это.
Есть нечто, называемое сопрограммы , которое известно на протяжении десятилетий. («Кнут и Хоппер» -класс «на десятилетия») Они являются обобщениями подпрограмм , в том смысле , что они не только получают и освобождают управление в операторе запуска и возврата функции, но и делают это в определенных точках ( точках приостановки ). Подпрограмма - это сопрограмма без точек подвеса.
Их легко и просто реализовать с помощью макросов C, как показано в следующей статье о "protothreads". ( http://dunkels.com/adam/dunkels06protothreads.pdf ) Прочтите его. Я буду ждать...
Суть этого в том , что макросы создают большой
switch
, иcase
метку в каждой точке подвески. В каждой точке приостановки функция сохраняет значение непосредственно следующейcase
метки, чтобы она знала, где возобновить выполнение при следующем вызове. И это возвращает контроль звонящему.Это делается без изменения видимого потока управления кодом, описанным в «protothread».
Теперь представьте, что у вас есть большой цикл, вызывающий все эти «протопотоки» по очереди, и вы одновременно выполняете «протопотоки» в одном потоке.
Этот подход имеет два недостатка:
Есть обходные пути для обоих:
И если бы у вас была поддержка компилятора для выполнения работы по перезаписи, которую выполняют макросы и обходной путь, ну, вы могли бы просто написать свой код прототипа, как вы и намеревались, и вставить точки приостановки с ключевым словом.
И это то, что
async
иawait
все: создание сопрограмм (без стеков).Сопрограммы в C # являются объектами (универсального или неуниверсального) класса
Task
.Я нахожу эти ключевые слова очень вводящими в заблуждение. Мое умственное чтение:
async
как "надёжный"await
как "приостановить до завершения"Task
как "будущее ..."Сейчас. Нам действительно нужно пометить функцию
async
? Помимо того, что он должен запускать механизмы переписывания кода, чтобы сделать функцию сопрограммой, он устраняет некоторые неоднозначности. Рассмотрим этот код.Предполагая, что
async
это не обязательно, это сопрограмма или нормальная функция? Должен ли компилятор переписать его как сопрограмму или нет? Оба могут быть возможны с различной возможной семантикой.источник