Дизассемблируем Python-циклы. Ассимиляция Гиперпространственного Фокала Социалистических Измерений!

Мой курс «Хардкорная веб-разработка» - course.to.digital
Книжный клуб Ботаним!, где мы читаем хорошие ИТ-книги: botanim.to.digital/
Telegram - t.me/t0digital
Препарируем Python-циклы по полной!
0:00 Стартуем
0:31 О чём речь
1:14 Всё дело в обходе структуры!
8:24 Надо просто вынести range за функции!
10:37 Что такое итерация?
19:39 Упрощаем код
20:09 Адовые тесты!
23:13 А если переписать на while?
24:11 while работает медленнее, чем for?
26:12 Выводы
Первое видео - • Ускоряем вложенные цик...
/****************** about ******************/
Меня зовут Алексей Голобурдин, я программирую с 2004 года и на этом канале делюсь своим опытом. Я основатель и руководитель компаний:
- Диджитализируй digitalize.team, разрабатываем сложные IT системы для бизнеса;
- Salesbeat salesbeat.pro, комплексный модуль доставки для интернет магазинов.
Telegram канал - t.me/t0digital
ВК - digitalize.team
RuTube - rutube.ru/channel/24802975/ab...
Дзен - dzen.ru/id/6235d32cb64df01e6e...

Пікірлер: 106

  • @user-ir4vd5yk4x
    @user-ir4vd5yk4x25 күн бұрын

    "для тех кто возбудился услышав пайтон и компилятор" .... поздравляю вы вылечены от импотенции при помощи пайтона

  • @user-oj2vj4rc5f

    @user-oj2vj4rc5f

    24 күн бұрын

    Обожаю

  • @NN-jx8kb
    @NN-jx8kb25 күн бұрын

    Спасибо вам за видео. Мне очень нравится ваша подача материала, всегда приятно смотреть и слушать

  • @t0digital

    @t0digital

    25 күн бұрын

    Спасибооо!

  • @losos6069
    @losos606925 күн бұрын

    1:16 > Поэтому у тебя такой результат получается т.к. тут речь про мой коммент под прошлым видосом, то отвечу) Я отметил в комментах что эксперемент проведен не совсем ЧИСТО и что кеши МОГЛИ повлиять на результат P.S. Я не из тех адептов которые пишут что ты неправильно итерации посчитал P.S.S. Братан, хорош, давай, давай, вперёд! Контент в кайф, можно ещё? Вообще красавчик! Можно вот этого вот почаще?

  • @roldexX
    @roldexX2 күн бұрын

    Раньше об этом не задумывался, а сейчас прошёлся по операциям и понял даже как посчитать разницу в итерациях, по сути в этих примерах отличается только количество раз прохождения точки вхождения в циклы, а именно там создаётся переменная

  • @Vjidowkdkcpapqkfjfw
    @Vjidowkdkcpapqkfjfw25 күн бұрын

    Это как после того что в питоне нет переменных - понял) Надо смотреть, будет больно, но полезно)

  • @7IdE
    @7IdE19 күн бұрын

    Вот от while на счетчиках я вообще такой подставы не ожидал. Т.е, у for под капотом будет создаваться итератор, который на каждой итерации будет илдить новый элемент. И все это это будет завернуто в try/except, чтобы ловить StopIteration. И все вот это дело быстрее чем счетчики в while?... Я аж у себя проверил - реально быстрее. Я так понимаю, тут прикол в том, что в случае со счетчиками в while мы там руками прописываем инкременты, а вот в случае for - там это уже прописано где-то глубоко под сишным капотом. Но это все равно какая-то прям мистика. Респект за такой видос!

  • @user-zn5nr1cr4b
    @user-zn5nr1cr4b25 күн бұрын

    Спасибо за видео! Справедливости ради хочется отметить, что если в цикле производится какая-то операция, по которой определяется условие его выхода, то while все же может быть быстрее :) К примеру, если часть вычислений уровнять (по примеру с видео): from functools import partial import timeit def for_loop(count: int): counter = 0 for _ in range(count): counter += 1 def while_loop(count: int): counter = 0 while counter counter += 1 x = timeit.timeit(partial(for_loop, 1_000_000), number=100) y = timeit.timeit(partial(while_loop, 1_000_000), number=100) print(x, y, x / y) #x=2.7985 y=2.026 d=1.381 то while окажется быстрее до 40%

  • @merzbow7
    @merzbow725 күн бұрын

    Если уж говорить про декартово произведение, то тут вложенный цикл и не нужен, можно обойтись одним for row, col in product(range(5), range(2)):

  • @t0digital

    @t0digital

    25 күн бұрын

    можно

  • @t0digital

    @t0digital

    25 күн бұрын

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

  • @harry-smith404
    @harry-smith40425 күн бұрын

    лайк чисто за разбор байткода, многим будет интересно(наверное), тк, полагаю, мало народу вообще смотрит, как оно работает под капотом

  • @RedkeiGost
    @RedkeiGost25 күн бұрын

    Минуточку! Эдак и до спецификации не далеко.

  • @notacatbeaver7853
    @notacatbeaver785318 күн бұрын

    Спасибо за пояснение к видео! А то алгопрогерский опыт не дал понять что имелось в виду под итерацией

  • @gnompirogov9259
    @gnompirogov925925 күн бұрын

    Алексей, спасибо за детальны разбор. Такой момент, мной, замечался ранее, около года назад. Но, вы, разобрали на достаточно детальных примерах. Интересно :))) Спасибо

  • @user-kt2pf5bf5m
    @user-kt2pf5bf5m25 күн бұрын

    Долго не мог понять, почему количество итераций разное, а потом написал эти 2 цикла и сразу понял)

  • @user-eg3jf9dw5c
    @user-eg3jf9dw5c25 күн бұрын

    надо перевести столь удачный термин на английский и попробовать на SO спросить, интересно что подумают.

  • @user-fx7pt8gd1s
    @user-fx7pt8gd1s25 күн бұрын

    13:03 вообще, оч хороший пример, потому что в нем играют роль не только сами накладные расходы на циклы, но и, например, всякие кэши и конвейеризации на процессоре. Поэтому компиляторы многих языков циклы разворачивают по возможности или "подразворачивают", то есть в теле цикла пишут N раз одно и тоже, и количество итераций делят на N

  • @shaltayb0ltay
    @shaltayb0ltay23 күн бұрын

    Автор ответил на все возникшие у меня при просмотре каверзные вопросы. Подписался. При этом укрепился в мнении, что python - язык, что позволяет быстро писать медленно работающий код.

  • @t0digital

    @t0digital

    23 күн бұрын

    Python на данный момент самый медленный из большой скриптовой тройки Node, PHP, Python. Но работа над его ускорением идет. Обещается пятикратный рост скорости. JIT вот завозят в 3.13

  • @leonidgrishenkov4183
    @leonidgrishenkov418323 күн бұрын

    Картинка офигенная)

  • @t0digital

    @t0digital

    23 күн бұрын

    Спасибо!

  • @gsm7490
    @gsm749025 күн бұрын

    Крутой материал! Это же все началось с «чистого кода», если не ошибаюсь? И вона куда занесло ) Я периодически начинаю переходить на плюсы или ржавчину, когда думаю о скоростях исполнения, но когда вспоминаю, сколько там всего надо написать, чтобы решить простую задачку, все проходит )

  • @km-academy_ru
    @km-academy_ru25 күн бұрын

    То что цикл несет дополнительные издержки, ясно уже интуитивно просто потому, что цп приходится исполнять инструкции оператора for

  • @john.darksoul
    @john.darksoul25 күн бұрын

    У меня есть подозрение, что самая тяжёлая операция в байткоде в начале - это GET_ITER, или что-то типа того. И получается, что итератор (а не итерация) создаётся либо 6 раз, либо 101 раз. Классическая тема, по-моему, просто питон это скрывает от пользователя. Скорее всего, если повторить этот тест с вложенными while со счётчиками, разницы не будет. Проверять я это, конечно, не буду, потому что мне лень :D

  • @vitaliy3521
    @vitaliy352125 күн бұрын

    Так эти накладные расходы никак не скалируются, т.е. если мы добавим в цикл какое-то полезное действие(sleep(0.1)), то эти десятитысячные секунды так и останутся десятитысячными, а время выполнения будет примерно одинаковым. Правильно же?

  • @t0digital

    @t0digital

    25 күн бұрын

    Да, об этом есть в выводах. Но 0.1с это ооочень до фига даже для медленного питона

  • @harry-smith404
    @harry-smith40425 күн бұрын

    13:02 ну я так понимаю это из-за использования итераторов в for циклах в питоне на каком си c циклом for (int i = 0; i короч, любое телодвижение - это процессорное время любое телодвижение x10^(10) - это фатальное процессорное время

  • @xeqxeq4287

    @xeqxeq4287

    25 күн бұрын

    Вот с Си не так всё очевидно. Если внутренний цикл поместится в кеш... Короче, надо конкретный случай смотреть и как оптимизирует компилятор(может вообще цикл развернуть)

  • @mikeofs1304

    @mikeofs1304

    25 күн бұрын

    В данном случае что там что там будет разнится. потому что циклы это джампы(гоуту кому как нравится), а это лишняя операция не самая легкая

  • @harry-smith404

    @harry-smith404

    25 күн бұрын

    @@xeqxeq4287 >Короче, надо конкретный случай смотреть это в любом языке, если ковыряться в этом, то надо разбираться, во что в итоге превращается исходный код

  • @dmitry-lz1ny
    @dmitry-lz1ny25 күн бұрын

    Если вы побудите в комьюнити других языков, то там не редко говорят, что в питоне очень хреново работает for и while. На том же C C++ в разы лучше, ну ладно это такое себе сравнение. В целом лучше избегать циклы в питоне. : )

  • @nakamasama

    @nakamasama

    25 күн бұрын

    А потом и сам Питон, а после и вообще всё программирование избегайте... Чем Вы предлагаете заменить циклы? Goto и спагетти-кодом?

  • @dmitry-lz1ny

    @dmitry-lz1ny

    25 күн бұрын

    @@nakamasama Так я не писал, что отказываться надо. Если их можно избежать, то лучше делать именно так. В любом случае те кто часто работает с математикой, те используют нумпай и аналоги (ну дата сатанисты) А отказаться от питона это будущее проекта, который превращается в хайлоад : )

  • @nakamasama

    @nakamasama

    25 күн бұрын

    @@dmitry-lz1ny , крутой ответ. Согласен, переход на другой язык качественно улучшает проект👍. И про нампай не поспоришь... Он ведь на С++ написан, а в Питоне просто оболочку имеет. Простите, но лично для меня избегать и отказаться в общем понимании значат одно и то же.

  • @ABVGDE546
    @ABVGDE54625 күн бұрын

    Я нубас, но коммент и лайк для продвижения. Ничего не пойму, но посмотрю

  • @MrLagger1996
    @MrLagger199625 күн бұрын

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

  • @Max-nr1bv
    @Max-nr1bv25 күн бұрын

    Что что в названии написано? 😂

  • @t0digital

    @t0digital

    25 күн бұрын

    Вся суть! База!

  • @alexusb9064
    @alexusb906425 күн бұрын

    модель клавиатуры подскажи плс.

  • @t0digital

    @t0digital

    25 күн бұрын

    keychron k3

  • @PlayGameToday
    @PlayGameToday25 күн бұрын

    Хорошо жить одному в просторном доме и заниматься программированием

  • @t0digital

    @t0digital

    25 күн бұрын

    мне тоже нравится

  • @user-zl5sp9yh1n

    @user-zl5sp9yh1n

    25 күн бұрын

    ​@@t0digital А нам нравится добротный контент который получается в такой хорошей обстановке.

  • @PlayGameToday

    @PlayGameToday

    25 күн бұрын

    @@t0digital Да, особенно хорошо, когда живешь один, нет жены, которая пилит. Молодец, я такой же.

  • @dmitrymalina8272
    @dmitrymalina827224 күн бұрын

    Не подскажете, что за тема у вас в vim? На гитхабе лежит ваш старенький vim.rc с Oceanic-Next, а тут явно что-то покрасивше)

  • @t0digital

    @t0digital

    23 күн бұрын

    gruvbox - хороша:)

  • @plathardstuck28
    @plathardstuck2825 күн бұрын

    если нужно использовать циклы в питоне - нужен не питон (c)

  • @AlexanderBorshak
    @AlexanderBorshak25 күн бұрын

    В том, что цикл несет накладные расходы, никто не спорит. В чем основной посыл - вложенный цикл с большим плечом ВНТУРИ медленнее вложенного с большим плечом снаружи. Верно? (Ну или наоборот - неважно.) Тогда предлагаю вам сделать такой эксперимент: меньшее плечо - 100, большее 1_000 (1 тысяча). Внутри самого внутреннего цикла какая-то емкая задача, скажем на 1 милисекунду - вызов CPU-bound функции, с подобранным временем примерно в 1мс, но всегда с одинаковыми данными, чтобы время работы не менялось. Теоретически прогон должен занять 100 * 1000 = 10_000 мс, то есть 10 секунд на саму работу ПЛЮС накладные расходы на циклы. Вот и сделать прогон для внешнего цикла с большим плечом, и с малым, и посмотреть, насколько разница в организации циклов будет влиять на результат, и будет ли она заметна вообще. А то еще окажется, что разница при изменении порядка циклов окажется 0,001% от всего времени работы программы, что делает усилия по такой оптимизации бессмысленными.

  • @t0digital

    @t0digital

    25 күн бұрын

    Я говорю в тч об этом в видео.

  • @AlexanderBorshak

    @AlexanderBorshak

    25 күн бұрын

    И если разница при таком тесте будет стремиться к нулю, то это - полагаю - и есть причина, по которой итерацией считают именно ЕДИНИЦУ РАБОТЫ, а не инициализацию и обновление счетчиков циклов. Затраты на инициализацию _в абсолютном большинстве случаев_ мизерны, и их просто не учитыват. В тех же случаях, когда они играют роль, обычно оптимизируют программу вплоть до ручного размещения памяти в регистрах - и это явно не случай Питона. Rust, C, Zig - да. Но не Питон, здесь это явная "экономия на спичках".

  • @t0digital

    @t0digital

    25 күн бұрын

    @@AlexanderBorshak нет, не в абсолютном большинстве. 1 миллисекунда, о которой вы говорите - это до хрена даже для пайтон

  • @AlexanderBorshak

    @AlexanderBorshak

    25 күн бұрын

    @@t0digital Скажем так: оптимизация с разворотом порядков цикла будет иметь смысл только в том случае, если время, затрачиваемое на инициализацию цикла сравнимо по времени с _единицей работы_ внутри этого цикла. Если разница будет уже на порядок (на единицу работы 10 нано-секунд, на инициализацию 1 нано-секунда, время взято с потолка), а тем более на порядки (100 к 1), то такая оптимизация уже теряет смысл. Намного лучше писать с учетом сложности алгоритмов - например, возможно, где-то использовав хеш-таблицу вместо массива (словарь вместо списка в терминах питона) мы сможем уменшить сложность алгоритма от квадратичной до линейной. Такая оптимизация намного важнее, чем попытка сэкономить 10 лишних наносекунд.

  • @mikeofs1304

    @mikeofs1304

    25 күн бұрын

    @@AlexanderBorshak Раскажи как ты собрался, например в расте, размещать "память в регистрах".

  • @finemechanic
    @finemechanic19 күн бұрын

    Вот это разбор - просто до атомного уровня!

  • @idoodl
    @idoodl25 күн бұрын

    31:09 я один заметил, что второй раз функция выдала -44% это как? Отрицательные значения мы понимаем, но каким образом при равном подходе (когда малый всегда значительно меньше большого) получилось отрицательное значение? (неужели где-то в кэше/еще чем-то происходит магия?) Вопрос без попытки в чем-то обвинить, просто рил не понял как такое произошло.

  • @t0digital

    @t0digital

    25 күн бұрын

    Такие измерения всегда надо проводить на множестве запусков, чтобы как раз исключить такие флуктуации. Почему оно возникло - какие-то действия в системе возможно наложились. Работает много процессов, им ОС выделяет время, может что-то в этот момент более приоритетное запускалось в этот момент по мнению ОС и это привело к такому результату

  • @user-gz4pi8ez5t
    @user-gz4pi8ez5t24 күн бұрын

    Тоже несколько лет назад спорил. Мне доказывали, что копирование файла с индикатором прогресса выполняется быстрей, чем без него 😂😂😂😂

  • @t0digital

    @t0digital

    24 күн бұрын

    А если отображение прогресса сделать в формате красивого на лету генерируемого 8к-видео с водопадом, птичками, листочками и мошками, чтоб комп просто визжал как сволочь - тогда файлы вообще копироваться мгновенно станут!

  • @darkhekromant
    @darkhekromant24 күн бұрын

    С итерациями все правильно, у каждого цикла свои итерации, почему они дожны объединяться? А если у тебя в одном цикле два вложенных разной длинны? Это сколько тогда у них в сумме итераций? :D

  • @programisli
    @programisli25 күн бұрын

    Твоя ошибка действительно в использовании слова итерации. Но в целом та ты прав. Если посмотреть на байт код, то циклы не бесплатные. 9-я и 10-я строки стоят сразу нескольких операций. Тело двух циклов выполняется 500 раз, но для того, чтобы выполнить 500 раз тело двух циклов в первом случае запуск двух циклов занял 600 раз - 10-я строка выполнялась 100 раз и 11-я выполнялась 500. Во втором случае запуск внешнего цикла происходил 5 раз, а внутреннего 500 раз. А глядя, во что превращается каждая из строк for, должно быть видно, на сколько получилась разница. Меньше запусков for приводит к экономии.

  • @Vorono4ka

    @Vorono4ka

    25 күн бұрын

    Почему слово итерация не подходит? Как минимум каждый из циклов итерируется по range'у, это уже можно посчитать как итерации (как автор видео и сделал с помощью my_range), или в названии операции в байт-коде питона тоже ошибка?😂

  • @alexusb9064
    @alexusb906425 күн бұрын

    ну ассемблер это тоже не то что исполняется процессором. и никаких циклов вообще не существует, у проца все эти циклы это всегда какое то сравнение (CMP, TEST) и условный переход (JE JZ JNE JNZ...) байты этих команд можно поискать в IA32 Arch от intel, это и будут те самые байты которые проц выполняет. Ежу понятно что чем больше команд надо выполнить тем дольше работает программа, если внешний цикл меньше то как минимум команд сравнения будет выполнено меньше, а значит и работать будет быстрее, но процы умеет в предсказание переходов (привет SPECTRE и MELTWOWN и уже с нмни) и научились заренне исполнять код, так что это даже микро-оптимизацией наверное не стоит считать, скорее всего это вообще не особо актуально.

  • @t0digital

    @t0digital

    25 күн бұрын

    Да, и об этом тоже есть в этом видео:)

  • @xeqxeq4287
    @xeqxeq428725 күн бұрын

    Вот его торкнуло 🤣🤣🤣 Мужик выдыхай!!! 😁😁😁

  • @AlexanderBorshak

    @AlexanderBorshak

    25 күн бұрын

    )))

  • @baloobear70
    @baloobear7025 күн бұрын

    Фрикциями?

  • @t0digital

    @t0digital

    25 күн бұрын

    Да!

  • @baloobear70

    @baloobear70

    25 күн бұрын

    @@t0digital это не может не радовать, дорогие друзья 😃

  • @user-fd7ce2em5y
    @user-fd7ce2em5y25 күн бұрын

    Не хочу ставить лайк. Всего лайков 128. Что-то это да значит) Пусть значит. P.S.: Обновил страницу, чтобы всё таки поставить лайк. На этот раз лайков было уже 193)

  • @tulliolevichivita5130
    @tulliolevichivita513025 күн бұрын

    имхо выгода от такой оптимизации будет стремиться к нулю, если внутри цикла будет стоять что-нить cpu-bound

  • @t0digital

    @t0digital

    24 күн бұрын

    Об этом есть в видео

  • @Verdgil
    @Verdgil25 күн бұрын

    А всё почему, а всё потому, что пайтон не очень оптимизирует, я сейчас вбил аналогичный код в C++, так вот он мне внутренние циклы просто свернул до умножения простого P.S. Писать то я всё равно продолжу на любимом питончике, но, конечно, его оптимизирующему компилятору до компилятора а-ля clang или gcc ой, как далеко

  • @t0digital

    @t0digital

    25 күн бұрын

    В 3.13 вроде jit завезут:)

  • @Verdgil

    @Verdgil

    25 күн бұрын

    ​​@@t0digitalне ну jit это лишь первый шаг, сишные компилятор просто свернул код до умножения 5*100 в одном случае и 100*5 во втором P.S. clang 15, apple version, O3

  • @t0digital

    @t0digital

    25 күн бұрын

    Да, Сишка есть Сишка

  • @Verdgil

    @Verdgil

    25 күн бұрын

    ​@@t0digitalи не поспоришь

  • @Verdgil

    @Verdgil

    25 күн бұрын

    ​@@t0digitalи не поспоришь... верим в развитие нашего любимого языка

  • @Vorono4ka
    @Vorono4ka25 күн бұрын

    Жду новых комментариев о том, что опять кто-то не прав и вообще всё не так и сам Гвидо говорил, что... 😂

  • @t0digital

    @t0digital

    25 күн бұрын

    Гвидо, молчи, Гвидо, не надо😂

  • @user-zl5sp9yh1n

    @user-zl5sp9yh1n

    25 күн бұрын

    Тут на ютубе есть парень который принимает участие в разработке питона, может у него спросите?😂

  • @mikeofs1304
    @mikeofs130425 күн бұрын

    Все правильно раскидал, и пример нормальный. Дурачки предлагающие размыть тяжелой операцией внутри - сводят одну задачу к совершенно другой. А итерация в твоем контексте - это один джамп в машинном коде, все отсальное это уже из совершенно других контекстов. И унижение этих "философов от cs'" при помощи байткода считаю абсолютно правильным. ЛайГ. И кстати индусский пример таки - пример трейдофа скорости на памятью И то же дичайше поддерживаю его добавление в методических целях

  • @andreymironov8169

    @andreymironov8169

    25 күн бұрын

    То есть питоновский FOR_ITER сводится в итоге к jump? Не увидел такого в видео. А тяжелая операция показывает, что оптимизация с малым и большим циклом бессмысленна, тем более в питоне, который вообще не про скорость 😊

  • @mikeofs1304

    @mikeofs1304

    25 күн бұрын

    @@andreymironov8169 раскажи мне чем на уровне машинного кода можно реализовать цикл кроме джампа? Спойлер loop это тоже джамп. Тяжелая операция это вырожденный случай общего. Или ьы не понимаешь таких слов?

  • @andreymironov8169

    @andreymironov8169

    25 күн бұрын

    @@mikeofs1304 где питон, а где машинный код?

  • @mikeofs1304

    @mikeofs1304

    25 күн бұрын

    @@andreymironov8169 в компьютере оба

  • @andreymironov8169

    @andreymironov8169

    25 күн бұрын

    ​@@mikeofs1304уровень умника понятен... иди котиков посмотри, они тоже в компьютере

  • @s_ivanov179
    @s_ivanov17925 күн бұрын

    34 минуты унижения адептов аптимызации в сфере веб технологий!

  • @junjul887
    @junjul88724 күн бұрын

    Ахахахахаха

  • @olegssh6452
    @olegssh645225 күн бұрын

    все функции с операциями сложения больших чисел лучше компилировать на Cython например для цикла инкрементирующего count 222222222 раза результаты: Cython: 5.83939254283905e-07 Python: 7.961033541010693 Cython выполнился быстрее на 1_363_332_384.09%

Келесі