Как стать автором
Обновить

Комментарии 28

Применение асинхронных механизмов при написании некоей программы означает, что эта программа будет выполняться быстрее, чем без использования подобных механизмов.
Нет.
Если добавить словосочетание «при определённых условиях», то прокатит )
А тогда придётся условия описывать, что сразу сделает описание не таким красивым.

По моему опыту, асинхронность может сделать программу медленнее. А может ничего не изменить. Может ускорить. В таком виде это звучит ни разу не оптимистично — а зачем мне тогда такая штука нужна? =)

ПС: просто это настолько частое заблуждение, что немножко больно каждый раз читать такие вещи.
А если серьёзно, то вообще данный вид асинхронности придумали не столько для скорости, сколько для того, чтобы не тратить ресурсы впустую на ожидание окончания каких-либо операций. Теоретически, пока мы ждём окончания какой-то async операции мы пока можем другой какой-то код повыполнять, который не зависит от результата этой операции. Но в итоге всё упирается в детали реализации и выгоды может, конечно, и не быть. А может и быть, если всё удачно сложилось.
Прекрасно это понимаю =)

Главная проблема в том, что этой информации часто не хватает в тексте — не хватает теоретического пояснения, что как и почему и что же в итоге даст асинхронность, как её правильно готовить.

Правильнее сказать что асинхронность ускоряет программу когда ожидается много задержек, например при ожидания ответа от удаленного сервера. В таком случае можем открыть несколько соединений и в каждом соединении отправлять запрос, ждать ответ, и обрабатывать его - и пока ждем ответ - будем отправлять новый запрос и т.д.

По ощущениями питон свернул куда-то не туда в плане асинхронщины
— Отлаживаться очень сложно, код избыточный
— Куча легаси и одноименных структур (к примеру есть два типа Future)
— Есть большие вопросы о том как правильно ловить исключения во вложенных корутинах
— По ощущениям люди пишут код дольше и ловят больше багов именно на асинхронном питоне
— У себя в кампании заметил что рост производительности в проектах на бою не больше 30%
— Очень сложно заставить питон грузить все ядра
— До версии 3.8 не было нормальной возможности в дебаге получить результат асинхронной функции
Как программист, у которого основной язык C#, должен заметить, что в C# async/await сделан во многом похожим образом, так что я думаю, тут довольно большая часть претензий должна быть к общеязыковой парадигме async/await, а не к Питону, который тут виноват только в некоторых особенностях реализации. В целом к этой парадигме просто надо привыкнуть и она, конечно, не панацея от всего.
Ну, насчет асинхронного программироварния, соглашусь.
А вот насчет грузить все ядра, мне так не кажется. Есть ведь модуль multipocessing.
Лично я для себя набросал небольшой фреймворк на его базе (по опыту разработки большой программы, используя опробованные подходы) и планирую польоваться им. Суть — работа выполняется в отдельных процессах, общение через очереди сообщений.
Мне такой подход нравится гораздо больше, чем накидать асинхронных вызовов функций. Главное преимущество такого подхода — можно ясно понимать, когда и что происходит.
Часто вообще бывает достаточно сделать map/reduce через pool.map/imap. Есть разные подходы к мультизадачности/асинхронности и это хорошо, когда они все реализованы в языке и доступны к использованию.
Ну, это в самых простых случаях. Иногда вообще можно через шелл процессы запускать.

А что не так с исключениями? Все на них жалуются, а я вот четыре года юзаю asyncio и проблем не испытывал

И всё же в русском языке принято переводить и говорить «параллельный запуск» и «параллельный режим», а не использовать кальку с английского «конкурентный».

Вот только это два разных термина, по идее ....

это разные вещи, параллельный когда в отдельных процессах, а значит потенциально на разных ядрах, а конкурентный когда по очереди в событийном цикле.
Да, вы правы. Поторопился.
НЛО прилетело и опубликовало эту надпись здесь
Логика в ваших словах есть, было бы интересно где увидеть эталонные определения терминов.

Если пишите о короутинах протона, то именно конкурентный.

Асинхронный код будет быстрее, если время расходуется не процессором, а ожидает ответа с другой стороны. Синхронный код остается ждать ответа, а асинхронный тем временем продолжает делать еще что-то полезное.
Наиболее разумное применение — скрейпинг. Пример: мне нужно было собрать данные с 4К страниц. Запустил синхронный код, вышло около 25 минут до завершения процесса. По результату обнаружил, что забыл еще один параметр прочитать и поэтому надо было повторять заново. Переписал на асинхронный — вышло около 2,5 минут. Ровно в 10 раз быстрее.

А потом сервер банит за DoS-атаку. Поэтому я не только не ускоряю свой скрейпинг, но ещё и искусственные задержки в пару секунд добавляю)

В моем случае такого риска не было.

Насколько знаю, иногда и такие задержки легко вычисляют, поэтому рекомендуется делать паузу рандомно.

Для глубокого и фундаментального понимания асинхрощины питона, а также её исторического контекста, рекомендую прочесть книгу про монументальный фреймворк Twisted от издательства O'Reily. Если вы ещё сомневаетесь, то всё что вам нужно знать, чтобы захотеть почитать — корутины питона проектировали под обратную совместимость с Twisted, и об этом явно указано в документации.

(про await) Такая конструкция означает, что программа будет выполняться до тех пор, пока не встретит await-выражение, после чего вызовет функцию и приостановит своё выполнение до тех пор, пока работа вызванной функции не завершится

Извиняюсь, а разве старый добрый вызов функции не делает вот это самое, что здесь описано?

… После этого возможность запуститься появится и у других корутин.


Одна корутина ждет ответа откуда-нибудь, тем временем другая делает что-нибудь еще.

Ну да, в этом и есть смысл параллельного исполнения.
Тем не менее, в статье совсем не раскрыто, в чём, собственно, разница между
await asyncio.sleep(1)
и старым добрым
time.sleep(1)

НЛО прилетело и опубликовало эту надпись здесь
Функция из примера возвращает не сумму последовательности чисел от 1 до заданного, а число из заданной позиции ряда Фибоначчи. При аргументе 10 значения совпадают (и сумма чисел от 1 до 10, и 10-е число из ряда Фибоначчи равны 55). Но если вы вызовете функцию с аргументом 11, то получите уже не 66, а 89.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий