Pull to refresh

Comments 55

Я ссылаюсь на The Computer Language Benchmarks Game уже больше десяти лет.

Больше десяти лет ссылаться на такой бесполезный источник. Этим можно гордится?

Как вы решаете проблемы невысокой производительности Python?

Для особой задачи существуют особый инструмент. Проблема производительности не должна волновать, если выбран Python. Если же этот вопрос стоит, то вы ошиблись в первоначальном выборе инструмента для решения задачи. В общем случае в сравнении C, C++ и JAVA, программный код на языке Python проще писать, отлаживать и сопровождать.

А так пробовать CPython, Jython, IronPython.
В общем случае в сравнении C, C++ и JAVA, программный код на языке Python проще писать, отлаживать и сопровождать

Я бы добавил "в определенных задачах". С и плюсы, как компилируемые, конечно, имеют вынужденные сложности с разработкой, но java и прочие интерпретируемые строго типизированные языки при определеном размере кода могут быть проще в написании (IDE, как правило, проще работать с языками "построже"), и в сопровождении (проверки на уровне компиляции это хорошо — в слишком гибких языках regression можно отслеживать только тестами. Не, TDD это неплохо, но когда тест надо писать на любой чих, чтобы ничего не свалилось, то это сомнительное свойство языка)

Именно так. У кроваво-энтерпрайзных языков есть свои преимущества. Не представляю, как тонну легаси говнокода на плохо типизированном языке можно сопровождать, проще наверно застрелиться. А в Java и C# такое — сплошь и рядом.
1С) С трудом, но можно.

Не надо кидаться в Java и равнть к другим. Легаси код понятие растяжимое: ему 1 год, 3 или 10 лет?
Тем более не забываем об анализаторах, которые умеют подсказывать (если уж не сам писал проект), где, что и как поменялось и что более не юзается в выбранной версии языка для проекта.
Далее, если речь идет о чистой Java (конечно с внешними либами, но без совсем уж жирных, которые именуют себя фреймворками), то там все просто и понятно, под свою задачу, есессно.

Я давно работаю на питоне и с «проблемами невысокой производительности» пока не сталкивался.
Но, например, если бы мне нужно было бы обсчитать массив чисел, и производительности бы не хватало, сегодня я попробовал бы связку Python+Numpy+Ctypes и поробовал бы написать работу с массивом чисел на Си и дергать ее из питона.
Ну или Cython, но не факт, что получиться написать быстрее, чем на Python+C. Я имею в виду скорость разработки.

Насколько я понимаю, описанная в статье проблема имеет влияние только когда есть много потоков, конкурирующих за процессор.
Во многих реальных задачах потоки ждут i/o операции большую часть времени, так что это может быть незаметно. На 100%cpu нечасто приходится работать. А в devops или нехитрой оптимизации (где питон часто используется и, на мой взгляд, особенно хорош) вообще ни о чем

Можно вместо потоков использовать процессы. И тогда GIL неактуален. Но, питон и сам по себе не очень шустрый. Но в 90 процентов случаев скорости вполне хватает.

Ну да — в этом сама суть.
Питон "человеческий" язык со своей областью применения.
Натягивание совы на глобус, чтобы быть "лучшим" языком… возможно, а оно надо?
Хайп вокруг питона последнее время меня смущает: никто не говорит, что скрипты на bash для автоматизации чего-то сложнее ls|grep|wc выглядят, как порождение марсиан, но, как только в питоне изменился синтакс print или ввели новые операторы — все дружно обсуждают кризис языка

Как вы решаете проблемы невысокой производительности Python?

Учу Crystal
UFO just landed and posted this here
UFO just landed and posted this here
А что за изменения? А то подумываю перейти на него.
UFO just landed and posted this here
Так Гвидо был прав с := и те, кто не понимал, зачем предлагается такая конструкция просто его задолбали.

Наверное, имеется в виду что-то из последнего самого скандального PEP 572.

:= и «самоснятие короны» — в новостях все было и было бы трудно пропустить если вы интересуетесь Python-ом.
Обе видел, но я лично не вижу ничего плохого ни в том ни в том, боялся увидеть в ответ что то вроде изменения лицензионной политики, уход в конкретную прикладную область самого языка (веб, анализ данных, т.п.), раскол на несколько разных веток и подобное. А тут всего лишь небольшие изменения синтаксиса и уход важной фигуры немного в сторону.
С уходом Гвидо, для широкой публики возникло определенное недопонимание, как будут приниматься решения о развитии языка. Не факт, что и раньше много людей знало, как это происходило, но была легенда, что Гвидо ван Россум — это тот человек, за которым остается последнее слово, и он не допустит необоснованных нововедений.
Пример деградации проекта, из за непродуманных действий — это ситуация с perl. Сколько лет уже пилят 6 версию, но стандартом она так и не стала. Сам язык есть, но это все еще 5 версия, которая осталась в своей нише, но это совсем не то, что было во времена рассвета.
А сколько лет параллельно живут 2 и 3 версии Питона?
Как утверждает википедия, версия питона 3.0 вышла 3 декабря 2008 года. Учитывая, что объем изменений в третьей ветке довольно велик, в прод python3 ушел где — то с версии 3.3, т. е, года 4 спустя.
С нетерпением жду возможность использовать обязательное указание типа и умение cpython использовать эту информацию для ускорения.
Cython и RPython вроде именно такие
в геймдеве, например, только для скриптинга…

Маленькая инди-игра EVE Online всё ещё на Stackless Python в клиенте и серверах, производительность затыкалась вставками C/C++.
UFO just landed and posted this here
Причиной невысокой производительности Python является его динамическая природа и универсальность.

Что-то статья как-то резко оборвалась. В начале рассматривалось сравнение с Javascript — там же почти все тоже самое, нет? Неужели при обращении к переменной ее тип не проверяется, в чем принципиальная разница?
Не могу сказать по составляющей, но у меня был одинаковый код на python и nodejs (описал комментом ниже). nodejs была заметно быстрее питона, но, к сожалению, у меня она не прижилась, так как питоновские биндинги типа numpy естественно выиграли у нативных JS-решений, не говоря уж о ML.
Код на NodeJS работает быстрее из-за того, что JS-движок V8 как раз с JIT-компилятором. При этом, насколько я помню попадавшуюся информацию, он сразу весь код компилирует в машинный. Не так круто, как Си или Си++, скорее, как JIT-компилятор JVM, но зато всё сразу.

Информация из разряда «когда-то мимо пробегало», потому что JS не зашёл: пишу на Python и C/C++. Если ошибаюсь, буду рад узнать более точные сведения.
Расскажу свой случай:

Написал некий подбор параметров для вычисления. сначала сделал это на Rust, заняло довольно много времени, так как это был первый подход к расту, без каких-то особенных оптимизаций получилось вполне примлемо: ~4млн данных подбирало 7 параметров (где-то 12млн комбинаций) на домашнем i5-7500 около 5 часов.

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

сначала с pandas — скорость была такая, что он и 1k данным считал больше минуты — это ни в какие ворота. Переписал всё исключтельно на numpy — скорость стала вполне приличной.
Но всё не верторизируешь, и одним numpy сыт не будешь — добавил перебор параметров как было раньше — и с каждым лишним if программа проседала на порядки, в итоге ETA подсчёта того что я описал в первом обзаце, показал что оно будет считаться несколько месяцев, что очень резко охладило желание использовать питон где-то за пределами ML.
сначала с pandas — скорость была такая, что он и 1k данным считал больше минуты — это ни в какие ворота. Переписал всё исключтельно на numpy — скорость стала вполне приличной.


Но ведь у pandas под капотом как раз numpy крутится, не может у них быть какого-то значимого различия в скорости. Возможно, вы в первом случае просто что-то сделали не так.
там код довольно простой: вначале было переписано 1 в 1 и прирост был сразу. потом ещё уже на numpy оптимизировал.
pandas довольно медленный (особенно если его неправильно готовить, например, итерировать по строкам). Даже в простых случаях накладные расходы сильно тормозят:
In [38]: arr = np.random.rand(1000, 10000)

In [39]: df = pd.DataFrame(arr)

In [40]: %timeit arr.mean(axis=1)
4.62 ms ± 114 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [41]: %timeit df.apply(np.mean, axis=1)
109 ms ± 1.43 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

In [42]: np.all(arr.mean(axis=1) == df.apply(np.mean, axis=1))
Out[42]: True
не итерировал. была одна группировка. аналогичное на сыром numpy работало значительно быстрее.

Удивительно, что в статье не упомянули numba. На мой взгляд, это самый простой, но при этом очень мощный способ увеличения производительности при минимальных изменениях в исходном коде.

Все это уже давно известно, ничего нового, никакого углубления в суть. Вот если бы автор, например, взял пример какой-нибудь функции на python и проанализировал ее байт-код, замерил бы скорость его компиляции и интерпретации и по регистрам проанализировал получившийся в итоге нативный код, сравнив его с аналогичным результатом на c# или c++, тогда я б поклонился. Была бы видна незаурядная работа, а так просто перечень общеизвестных истин. Кстати, что cpython делает с байт-кодом в pyc файлах? Он его просто интерпретирует, не компилируя в нативный, или каждый раз перекомпилирует? — из статьи так это и не ясно

Кстати, что cpython делает с байт-кодом в pyc файлах? Он его просто интерпретирует, не компилируя в нативный, или каждый раз перекомпилирует?

Именно интерпретирует. Перекомпиляцию производит, если изменяется исходный код. Как определяет, я не в курсе, просто не было интересно. По сути, сохранение этих файлов несколько ускоряет запуск программы.
Oracle не так давно достаточно интересно подошла к рантайму для различных языков программирования, включая Python, и предварительные результаты для динамических языков выглядят вполне неплохо youtu.be/mMmOntDWSgw?t=678. С учетом того, что GraalVM позволяет генерировать в том числе и нативный код, то в теории увеличивается не только общая производительность, но и время старта программ.
Ну, пока это не питон, а скорее эксперимент. Они сами это честно пишут.

Стоит добавить про numba — в некоторых случаях очень хорошо ускоряет код

Ключевые слова: процессы, asyncio, numpy, cupy, numba, cython решают все проблемы с производительностью.
Питон — это не числодробилка. 99% времени программа на Питоне чего-нибудь ждет: ответа от БД, чтения данных с диска, прихода пакета по сети, пользовательского ввода.

Если мне нужна числодробилка, я напишу программу на С (может даже с OpenCL). Если мне нужна программа, которая вычитывает из последовательного порта данные, пакует их в XML и пуляет на удаленный сервер по HTTPS с авторизацией по сертификатам — я напишу ее на Python. Потому что так проще, удобнее и быстрее.
Потому что Python это язык для управления обвесом и высокоуровневой логики. А числодробилку запихивают в тот самый обвес. Например, в NumPy. И не пытаются пробивать лбом стену.
ну так есть же форки процессов в питоне, и ими активно пользуются для распараллеливания выполнения задач.
Как вы решаете проблемы невысокой производительности Python?

Поскольку Python все более и более популярен в научной среде, эта проблема решается использованием библиотек с высокой производительностью. Для многих вычислительных задач и обработки данных хватает производительности numpy, scipy, numba, pandas. Для чего-то более хитрого можно написать основную часть на C/C++/Cython, а Python использовать как высокоуровневую обертку. Еще есть Dask, который для определенных задач обещает довольно простой параллелизм, масштабируемый до суперкомпьютеров, но я им пока не пробовал пользоваться.

+ расширения SciPy и ScientificPython
скорость выполнения может и не очень, но скорость разработки сервисных утилит просто решает.
PS: PyQt отлично помогает избавиться от проблем производительности в GUI.
и используемые потоки будут интенсивно использовать подсистему ввода-вывода (например, если они будут работать с сетью или с диском), тогда можно будет наблюдать последствия того, как GIL управляет потоками. Вот как это выглядит в случае использования двух потоков, интенсивно нагружающих процессов.
«Смешались люди-кони», как раз IO работа параллелится замечательно, а вот для CPU нагрузки* потоки не помогут.
Но это опять же зависит от задачи, если вы будете делать задачу сжатия данных (архиватор), то решение по скорости будет сопоставимо с С/С++.
Питон надо рассматривать как «мастер»-язык (код который управляет другим кодом), поэтому хорошо знать не просто питон а связку Python-C++ или Python-Cython, тогда вопросы скорости отпадут.
Питон в целом плохо подходит для высокопроизводительных задач. Это не его ниша. На нем удобно всякие инструменты создавать да прототипы.
Но если все же надо его то numpy (при правильном применении) или какая-нибудь другая domain-specific библиотека дает прекрасную однопоточную производительность сочетая скорость C с удобством Python.
Чисто питоновские решения следует запускать на PyPy — это дает ускорение на порядок а то и на два.
Уважаемые читатели! Как вы решаете проблемы невысокой производительности Python?

Переходом на Julia.
.NET CIL (это то же самое, что .NET Common-Language-Runtime, CLR)

CIL далеко не то же самое что и CLR!!!

Да, в Python приходится думать что, как и почему. Но вариантов ускорить работу кода — море.


  • Самый хороший способ — векторизация. Если есть возможность работать не с отдельными числами, а с массивами, а ещё лучше с матрицами, то надо так и делать — передавать массивы/матрицы и работать с ними прямо целиком. Тогда и Numpy, да и Pandas тоже, вполне себе летают.
  • Если векторизировать нельзя и нужно обрабатывать отдельные числа внутри длинных циклов, то можно попробовать Numba, она с такими случаями хорошо справляется.
  • Если есть предположение, что при обработке могут повторяться одинаковые данные, с которыми производятся "тяжёлые" вычисления, то хорошо работает кэширующий декоратор @functools.lru_cache
  • Если простаивают ядра процессора, то можно использовать в каких-то случаях Dask (хотя у меня с ним всё время глюки вылазили, может просто я его не умею готовить), а в каких-то простейший Pool по парадигме map -> reduce. При грамотном подходе (достаточном размере порций и равномерности разбиения данных) это даст реальное ускорение, близкое к числу ядер процессора. Главное, не вылезать за память при этом. Как показывает практика, крэша при этом не будет (что меня удивило), но активная работа со свопом гасит весь эффект от ускорения.
Sign up to leave a comment.