|
Зачем нужен await?
|
|||
---|---|---|---|
#18+
Думаю многие сталкивались с ключевым словом await в языках, применяющих async/await паттерн для асинхронного программирования. Основное ограничение, это использование только в async-функциях, это понятно. Вопрос такой. Почему бы вообще не отказаться от этого ключевого слова и необходимости его употребления, ведь компилятор может определить наличие вызова асинхронного метода и сам выполнить его асинхронно? Понятно, что наличие ключевого слова await позволяет, допустим, собрать все вызовы в коллекцию и эвейтить её, или даже вообще не эвейтить, а выполнить без ожидания, или вернуть awaitable результат (Task, promise, etc.), но для подобного, более редкого, употребления можно было сделать специальный синтаксис. ... |
|||
:
Нравится:
Не нравится:
|
|||
31.07.2018, 22:50 |
|
Зачем нужен await?
|
|||
---|---|---|---|
#18+
hVosttДумаю многие сталкивались с ключевым словом await в языках, применяющих async/await паттерн для асинхронного программирования. Основное ограничение, это использование только в async-функциях, это понятно. Вопрос такой. Почему бы вообще не отказаться от этого ключевого слова и необходимости его употребления, ведь компилятор может определить наличие вызова асинхронного метода и сам выполнить его асинхронно? Понятно, что наличие ключевого слова await позволяет, допустим, собрать все вызовы в коллекцию и эвейтить её, или даже вообще не эвейтить, а выполнить без ожидания, или вернуть awaitable результат (Task, promise, etc.), но для подобного, более редкого, употребления можно было сделать специальный синтаксис. Тебе вообще зачем __асинхронный__ вызов нужен? Наверное, чтобы он выполнялся параллельно с остальным кодом... А как оно будет выполняться параллельно, если ты тут же будешь ждать результат асинхнонного вызова? ... |
|||
:
Нравится:
Не нравится:
|
|||
01.08.2018, 00:05 |
|
Зачем нужен await?
|
|||
---|---|---|---|
#18+
MasterZivТебе вообще зачем __асинхронный__ вызов нужен? Наверное, чтобы он выполнялся параллельно с остальным кодом... А как оно будет выполняться параллельно, если ты тут же будешь ждать результат асинхнонного вызова? Похоже, вы очень сильно путаете понятия. Вот вам ссылка почитать Вкратце, асинхронный вызов мне нужен, чтобы I/O операции не блокировали рабочий поток из пула. Запуск подобного ожидания в параллельном потоке, это костыль, не решающий проблемы, но позволяющий, например, не блокировать единственный UI поток. В контексте серверных веб-приложений, подобный финт ушами вообще бесмысленнен. А в контексте, например, JavaScript и вовсе невозможен (не будем брать в расчёт не так давно появившиеся Web Workers). В общем, вернёмся к вопросу. Уточню, откуда ноги растут у вопроса. Проблемы две: 1. избыточность повсеместного ключевого слова await, если есть какое-то подозрение, что код модуля будет исполнять асинхронные методы, он тоже должен быть асинхронным. 2. забыли await, получили проблемы, особенно, если мы не ожидаем результат, а только сам факт асинхронного исполнения (async void). ... |
|||
:
Нравится:
Не нравится:
|
|||
01.08.2018, 00:27 |
|
Зачем нужен await?
|
|||
---|---|---|---|
#18+
hVostt, ситуации разные бывают, с await больше возможностей для разработчика Код: c# 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41.
... |
|||
:
Нравится:
Не нравится:
|
|||
01.08.2018, 01:51 |
|
Зачем нужен await?
|
|||
---|---|---|---|
#18+
Тогда после введения этой особенности получилось бы нарушение обратной совместимости. До нее тот же самый код бы просто запускал метод. А после нее эвейтил бы таску. Причем в документации бы пришлось писать что var x = y() ведёт себя по разному для методов возвращающих такску и прочие типы ... |
|||
:
Нравится:
Не нравится:
|
|||
01.08.2018, 06:17 |
|
Зачем нужен await?
|
|||
---|---|---|---|
#18+
LR Код: c# 1. 2. 3. 4. 5. 6.
Это очень странный код, поясните, зачем вы используете здесь ContinueWith вместе с await? Код: c# 1. 2. 3.
По поводу второго "не нужно". Это распространённая ошибка. Если приложение нормально завершит свою работу раньше, чем ваш Task, то работа может быть прервана на середине и код в ContinueWith вообще не выполнится. И без await контекст синхронизации нужно передавать вручную (актуально для UI и для ASP.NET, но не Core). ... |
|||
:
Нравится:
Не нравится:
|
|||
01.08.2018, 08:35 |
|
Зачем нужен await?
|
|||
---|---|---|---|
#18+
WebSharperТогда после введения этой особенности получилось бы нарушение обратной совместимости. До нее тот же самый код бы просто запускал метод. А после нее эвейтил бы таску. Т.е. кроме обратной совместимости, других проблем вы не видите? Думаете, если бы язык проектировался заново, типа новая супер-мажорная версия, без обратной совместимости, от ключевого слова await могли бы отказаться? WebSharperПричем в документации бы пришлось писать что var x = y() ведёт себя по разному для методов возвращающих такску и прочие типы Если бы async был частью контракта, а не реализации, то компилятор бы скрывал таску, y() при этом возвращал результат функции, а не awaitable объект в контексте использования. Проблема в том, что возвращаемый результат типа Task ещё не говорит о том, что это асинхронный метод. ... |
|||
:
Нравится:
Не нравится:
|
|||
01.08.2018, 08:41 |
|
Зачем нужен await?
|
|||
---|---|---|---|
#18+
MasterZivhVosttДумаю многие сталкивались с ключевым словом await в языках, применяющих async/await паттерн для асинхронного программирования. Основное ограничение, это использование только в async-функциях, это понятно. Вопрос такой. Почему бы вообще не отказаться от этого ключевого слова и необходимости его употребления, ведь компилятор может определить наличие вызова асинхронного метода и сам выполнить его асинхронно? Понятно, что наличие ключевого слова await позволяет, допустим, собрать все вызовы в коллекцию и эвейтить её, или даже вообще не эвейтить, а выполнить без ожидания, или вернуть awaitable результат (Task, promise, etc.), но для подобного, более редкого, употребления можно было сделать специальный синтаксис. Тебе вообще зачем __асинхронный__ вызов нужен? Наверное, чтобы он выполнялся параллельно с остальным кодом... А как оно будет выполняться параллельно, если ты тут же будешь ждать результат асинхнонного вызова? +1 ... |
|||
:
Нравится:
Не нравится:
|
|||
01.08.2018, 09:27 |
|
Зачем нужен await?
|
|||
---|---|---|---|
#18+
hVosttПо поводу второго "не нужно". Это распространённая ошибка. Если приложение нормально завершит свою работу раньше, чем ваш Task, то работа может быть прервана на середине и код в ContinueWith вообще не выполнится. И без await контекст синхронизации нужно передавать вручную (актуально для UI и для ASP.NET, но не Core). Это не ошибка, так задумано, если задание не выполнится до окончания работы приложения - это нормально, иначе задумано с sometask. Повторю, ситуации могут быть разными, await дает еще одну степень свободы - и это хорошо. ... |
|||
:
Нравится:
Не нравится:
|
|||
01.08.2018, 09:28 |
|
Зачем нужен await?
|
|||
---|---|---|---|
#18+
hVosttВопрос такой. Почему бы вообще не отказаться от этого ключевого слова и необходимости его употребления, ведь компилятор может определить наличие вызова асинхронного метода и сам выполнить его асинхронно? как вы правильно после заметили это не контракт, а реализация. контрактом является возврат интерфейса в котором есть управление задачей и получение результата. Т.е. компилятор не может вызвать метод асинхронно, await - синтаксический сахар, он просто вызывает методы ожидания возвращаемого интерфейса и попутно трасирует в него часть своей реализации. Принципиальной проблемы в использовании await вне асинхронного метода нет, собственнно в плюсах так можно делать без проблем. hVosttПонятно, что наличие ключевого слова await позволяет, допустим, собрать все вызовы в коллекцию и эвейтить её, или даже вообще не эвейтить, а выполнить без ожидания, или вернуть awaitable результат (Task, promise, etc.), но для подобного, более редкого, употребления можно было сделать специальный синтаксис. а как тогда должен себя вести код генерируемый компилятором? всегда ждать завершения? тогда 21619662 вполне уместен запоминать что переменная не переменная и её нужно проверять? тогда встаёт вопрос эффективности, фактически придётся делать ленивый вызов при использовании переменной, следить за ней, что в массовом порядке накладно. ... |
|||
:
Нравится:
Не нравится:
|
|||
01.08.2018, 10:01 |
|
Зачем нужен await?
|
|||
---|---|---|---|
#18+
hVosttТ.е. кроме обратной совместимости, других проблем вы не видите? Думаете, если бы язык проектировался заново, типа новая супер-мажорная версия, без обратной совместимости, от ключевого слова await могли бы отказаться? При этом можно было бы ввести другое умолчание (соответственно для поведения когда мы продолжаем исполнение, а не возвращаем управление вызвавшему методу). Т.е. у нас есть 3 действия - получить таску и что-то с ней сделать. Вернуть управление вызвавшему методу. Подождать пока вызванный метод закончится. Нам их надо как-то разграничить. ... |
|||
:
Нравится:
Не нравится:
|
|||
01.08.2018, 12:49 |
|
Зачем нужен await?
|
|||
---|---|---|---|
#18+
LRЭто не ошибка, так задумано, если задание не выполнится до окончания работы приложения - это нормально, иначе задумано с sometask. Повторю, ситуации могут быть разными, await дает еще одну степень свободы - и это хорошо. Спорить не буду. Лично я считаю, что запуск задач по принципу fire and forget должен осуществляться через планировщик заданий, и нормальное завершение программы не должно осуществляться путём terminate запущенных потоков. Либо нужно дожидаться выполнения всех заданий, либо посылать сигнал с требованием немедленного завершения работ, как минимум через CancellationToken, если мы говорим про C#. Так что это выглядит как ошибка и никак иначе. LRПовторю, ситуации могут быть разными, await дает еще одну степень свободы - и это хорошо. Проблема в том, что "ещё одна степень свободы" выливается в описанные выше мною проблемы. ... |
|||
:
Нравится:
Не нравится:
|
|||
01.08.2018, 12:53 |
|
Зачем нужен await?
|
|||
---|---|---|---|
#18+
kealon(Ruslan)как вы правильно после заметили это не контракт, а реализация. контрактом является возврат интерфейса в котором есть управление задачей и получение результата. Т.е. компилятор не может вызвать метод асинхронно, await - синтаксический сахар, он просто вызывает методы ожидания возвращаемого интерфейса и попутно трасирует в него часть своей реализации. Если мы говорим про C#, это довольно смелое утверждение насчёт "просто вызывает методы ожидания". Я спорил с Джоном Скитом на тему является ли await синтаксическим сахаром, и он меня убедил, что да, является. Но await принуждает компилятор строить конечный автомат без накладных расходов на количество кода в продолжении. А также разбирается с исключениями и контекстом синхронизации. В JavaScript да, это сахар, превращающийся в промисы. Конечно, из-за отсутствия контракта, компилятор не может сам сделать await , значит при его наличии, это можно было сделать, так? kealon(Ruslan)а как тогда должен себя вести код генерируемый компилятором? Он должен увидеть вызов асинхронного метода и выполнить его асинхронно, и не позволять дёргать асинхронные методы за пределами асинхронного контекста (асинхронного метода). kealon(Ruslan)всегда ждать завершения? тогда 21619662 вполне уместен Я не понимаю, почему до сих пор много людей путают конкурентность и асинхронность. Нет, не уместен. Давайте напомню, в JavaScript нельзя выполнить код параллельно. Можно выполнить ... |
|||
:
Нравится:
Не нравится:
|
|||
01.08.2018, 13:00 |
|
Зачем нужен await?
|
|||
---|---|---|---|
#18+
.. можно выполнить код асинхронно. kealon(Ruslan)запоминать что переменная не переменная и её нужно проверять? тогда встаёт вопрос эффективности, фактически придётся делать ленивый вызов при использовании переменной, следить за ней, что в массовом порядке накладно. При наличии контракта, видим, что метод асинхронный, значит выполняем его асинхронно. Т.е. компилятор сам вставляет await там, где он итак должен был быть написан программистом. ... |
|||
:
Нравится:
Не нравится:
|
|||
01.08.2018, 13:09 |
|
Зачем нужен await?
|
|||
---|---|---|---|
#18+
WebSharper https://softwareengineering.stackexchange.com/questions/328087/why-are-promises-not-awaited-by-default SONote that a function being async doesn't turn it into something completely different, it just enables some syntax. A normal function returning a promise is just as asynchronous as a function marked with async. The await serves as a warning sign "the world may have changed in the mean time". 1. await may be easier than multi threading, but it's still very error prone. During code review you have to look at each await, thinking "does the function rely on any information obtained before the await still being the same? Is this guaranteed?". Without an explicit await, you have to do so at every function invocation. 2. Backwards compatibility. With your proposal code behaves completely different if the browse/runtime supports awaiting or not. 3. If your code doesn't want to deal with awaiting, it needs to insert an async at every call to an externally defined function, just in case it returns a promise. 4. Performance. The runtime needs to insert an if result is a promise then await check at every method call. Ok. 1. мы хотим видеть вызовы await в коде, но IDE мог бы подсвечивать, находить и показывать такие вызовы. 2. обратная совместимость, аргумент. ок. 3. если я не хочу эвейтить, то для этого нужен отдельный синтаксис, потому что в 90% (если не больше) случаев нужно эвейтить. 4. только для нетипизированных языков, таких как JavaScript, это является проблемой. но и она решается точно также, как решаются все остальные проблемы отсутствия типизации. в общем, пока только обратная совместимость выглядит как преграда. ну ещё несколько лет нужно, чтобы люди привыкли к парадигме. ... |
|||
:
Нравится:
Не нравится:
|
|||
01.08.2018, 13:25 |
|
Зачем нужен await?
|
|||
---|---|---|---|
#18+
hVostt, давайте в реализации шарпа, и плавно к нативу в плюсах из которого видно куда что прыгает любой асинхронный метод в шарпе возвращает контракт IASync<T> на получение значения далее с ним надо что-то делать собственно await это такой сахар который одновременно ждёт вычисления IASync<T> и мониторит не отменили ли головной метод и если отменили "трубит" полученному контракту "СТОП" тут надеюсь всё понятно как это всё выглядит изнутри плюсов: вызвали аснхронный метод, собственно он возвращает контракт IASync<T> и тут можно с ним делать что угодно: подождать вызвать другой метод и пр. как это может быть в плане реализации асинхронного метода: тут куча вариантов: асинхронная функция ОС, запуск обёрнутой задачи в пул и пр. пр. теперь: hVosttНо await принуждает компилятор строить конечный автомат без накладных расходов на количество кода в продолжении. А также разбирается с исключениями и контекстом синхронизации.ничего он не выдумывает, он просто вставляет код ожидания hVosttКонечно, из-за отсутствия контракта, компилятор не может сам сделать await , значит при его наличии, это можно было сделать, так?у него только контракт (IASync<T>) и есть, он и вызывает один из его методов, на саму реализацию он не влияет hVosttkealon(Ruslan)а как тогда должен себя вести код генерируемый компилятором? Он должен увидеть вызов асинхронного метода и выполнить его асинхронно, и не позволять дёргать асинхронные методы за пределами асинхронного контекста (асинхронного метода). kealon(Ruslan)всегда ждать завершения? тогда 21619662 вполне уместен Я не понимаю, почему до сих пор много людей путают конкурентность и асинхронность. Нет, не уместен. ему вообще по барабану, у компилятора только контракт на ожидание выполнения непонятно чего Код: c# 1. 2.
куда физически вставлять await? ... |
|||
:
Нравится:
Не нравится:
|
|||
01.08.2018, 13:29 |
|
Зачем нужен await?
|
|||
---|---|---|---|
#18+
hVostt.. можно выполнить код асинхронно. kealon(Ruslan)запоминать что переменная не переменная и её нужно проверять? тогда встаёт вопрос эффективности, фактически придётся делать ленивый вызов при использовании переменной, следить за ней, что в массовом порядке накладно. При наличии контракта, видим, что метод асинхронный, значит выполняем его асинхронно. Т.е. компилятор сам вставляет await там, где он итак должен был быть написан программистом.ещё раз повторю: "асинхронный метод в реализации шарпа значит, что возвращается контракт на получение значения" т.е. в нативе это какой-то стаб который, например, кидает задачу в пул на выполнение своего кода и возвращает интерфейс по ожиданию его завершения\отмены\получению результата и пр. ... |
|||
:
Нравится:
Не нравится:
|
|||
01.08.2018, 13:42 |
|
Зачем нужен await?
|
|||
---|---|---|---|
#18+
kealon(Ruslan)собственно await это такой сахар который одновременно ждёт вычисления IASync<T> и мониторит не отменили ли головной метод и если отменили "трубит" полученному контракту "СТОП" Ничего он не мониторит, а сигнализацию прерывания надо пробрасывать самому. Сахар превращает метод в конечный автомат. Это можно посмотреть в дизассемблере IL, для асинхронного и синхронного вызовов. С ручным ожиданием через GetAwaiter и через await. Сгенерированный код будет абсолютно разный. kealon(Ruslan)как это всё выглядит изнутри плюсов: вызвали аснхронный метод, собственно он возвращает контракт IASync<T> и тут можно с ним делать что угодно: подождать вызвать другой метод и пр. как это может быть в плане реализации асинхронного метода: тут куча вариантов: асинхронная функция ОС, запуск обёрнутой задачи в пул и пр. пр. Из плюсов, да и в C# тоже, весь код, который генерит await можно написать и самостоятельно. Чудеса начинаются, когда среди кучи последовательных и вложенных await доходим до функций, выполняющих непосредственно I/O операции, которые и "отпускают" поток восвоясь. А когда результат будет получен, будет выдернут любой свободный поток, который продолжит выполнение оставшегося кода. Вот здесь суть, которую многие упускают, когда пытаются "на пальцах" строить свои объяснения того, как это устроено. Это и правда выглядит так, как будто оставшийся кусок метода после await тупо завернули в коллбек. Но это наивно так полагать. kealon(Ruslan)hVosttНо await принуждает компилятор строить конечный автомат без накладных расходов на количество кода в продолжении. А также разбирается с исключениями и контекстом синхронизации.ничего он не выдумывает, он просто вставляет код ожидания Куда вставляет? Кто код ожидания будет выполнять? Что там со стеком? Могу ли я ожидать огромное количество асинхронных операций, с небольшим количеством рабочих потоков? kealon(Ruslan)у него только контракт (IASync<T>) и есть, он и вызывает один из его методов, на саму реализацию он не влияет Пока нет такого контракта, который напрямую говорит, что этот метод является асинхронным. Для await подойдёт любой объект, у которого есть метод GetWaiter(). Этого недостаточно, так как те же Task используются и для многопоточного программирования, как часть TPL. kealon(Ruslan)ему вообще по барабану, у компилятора только контракт на ожидание выполнения непонятно чего Код: c# 1. 2.
куда физически вставлять await? Вот сюда. И только при условии, что метод, в котором находится этот код помечен как async. ... |
|||
:
Нравится:
Не нравится:
|
|||
01.08.2018, 14:28 |
|
Зачем нужен await?
|
|||
---|---|---|---|
#18+
kealon(Ruslan)т.е. в нативе это какой-то стаб который, например, кидает задачу в пул на выполнение своего кода и возвращает интерфейс по ожиданию его завершения\отмены\получению результата и пр. Т.е. будете ждать выполнение i/o операций на выделенном пуле потоков? Мдя... ... |
|||
:
Нравится:
Не нравится:
|
|||
01.08.2018, 14:30 |
|
Зачем нужен await?
|
|||
---|---|---|---|
#18+
hVosttВопрос такой. Почему бы вообще не отказаться от этого ключевого слова и необходимости его употребления, ведь компилятор может определить наличие вызова асинхронного метода и сам выполнить его асинхронно? Если я правильно понял, то ты хотел предложить не использовать await ? Но тогда как компилятор поймёт, до какого момента ему ждать ? Код: c# 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14.
... |
|||
:
Нравится:
Не нравится:
|
|||
01.08.2018, 14:34 |
|
Зачем нужен await?
|
|||
---|---|---|---|
#18+
Valery_BЕсли я правильно понял, то ты хотел предложить не использовать await ? Не использовать ключевое слово await, в контексте, где его использование очевидно. Такой контекст есть. Valery_B Код: c# 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26.
Первый случай это запуск таски в отдельном потоке, последующий await приводит только к асинхронному ожиданию (о чём было сказано 21619662 ), а не асинхронному выполнению. Во втором случае, функция помечена async , значит вызов любой асинхронной функции должен быть асинхронным, если это не указано каким-то определённым образом иначе. ... |
|||
:
Нравится:
Не нравится:
|
|||
01.08.2018, 14:50 |
|
Зачем нужен await?
|
|||
---|---|---|---|
#18+
Код: c# 1. 2. 3. 4. 5. 6. 7. 8.
... |
|||
:
Нравится:
Не нравится:
|
|||
01.08.2018, 14:52 |
|
Зачем нужен await?
|
|||
---|---|---|---|
#18+
hVosttkealon(Ruslan)как это всё выглядит изнутри плюсов: вызвали аснхронный метод, собственно он возвращает контракт IASync<T> и тут можно с ним делать что угодно: подождать вызвать другой метод и пр. как это может быть в плане реализации асинхронного метода: тут куча вариантов: асинхронная функция ОС, запуск обёрнутой задачи в пул и пр. пр. Из плюсов, да и в C# тоже, весь код, который генерит await можно написать и самостоятельно. Чудеса начинаются, когда среди кучи последовательных и вложенных await доходим до функций, выполняющих непосредственно I/O операции, которые и "отпускают" поток восвоясь. А когда результат будет получен, будет выдернут любой свободный поток, который продолжит выполнение оставшегося кода. Вот здесь суть, которую многие упускают, когда пытаются "на пальцах" строить свои объяснения того, как это устроено. Это и правда выглядит так, как будто оставшийся кусок метода после await тупо завернули в коллбек. Но это наивно так полагать.не выдумывайте, там обычный линейный код hVosttkealon(Ruslan)пропущено... ничего он не выдумывает, он просто вставляет код ожидания Куда вставляет? Кто код ожидания будет выполнять? Что там со стеком? Могу ли я ожидать огромное количество асинхронных операций, с небольшим количеством рабочих потоков?ожидание выполняет реализатор контракта IAsync<T> в частности с IO, для этого достаточно текущую нить отдать "планировщику" и переключиться на выполнение другой задачи. Можете ... |
|||
:
Нравится:
Не нравится:
|
|||
01.08.2018, 14:57 |
|
Зачем нужен await?
|
|||
---|---|---|---|
#18+
hVostt, Для меня как раз наоборот - первый случай абсолютно очевиден, а второй - наоборот. Не понятно, что должна сделать эта процедура выполняя первый и второй оператор. И в каком потоке. Код: c# 1. 2. 3. 4. 5. 6. 7.
... |
|||
:
Нравится:
Не нравится:
|
|||
01.08.2018, 15:02 |
|
|
start [/forum/topic.php?fid=20&fpage=28&tid=1399271]: |
0ms |
get settings: |
11ms |
get forum list: |
14ms |
check forum access: |
4ms |
check topic access: |
4ms |
track hit: |
40ms |
get topic data: |
8ms |
get forum data: |
2ms |
get page messages: |
92ms |
get tp. blocked users: |
2ms |
others: | 13ms |
total: | 190ms |
0 / 0 |