Почему с быстрее python
Перейти к содержимому

Почему с быстрее python

  • автор:

Сравнение скорости Python и C++

Автор этой статьи делает сравнение скорости выполнения одной и той же программы на Python и C++. С++ естественно быстрее, но насколько?

Прим. ред. Это перевод статьи Назера Тамими. Мнение редакции может не совпадать с мнением автора оригинала.

Есть миллион причин любить Python (особенно если вы дата-сайентист). Но насколько Python отличается от низкоуровневых языков, таких как Си и C++? В этой статье я собираюсь сделать сравнение скорости Python и C++, на очень простом примере.

Мы будем генерировать все возможные k-меры ДНК, для фиксированного
значения “k”. О том, что такое k-меры, я расскажу чуть позже. Этот пример был выбран потому, что многие задачи обработки и анализа данных связанные с геномом, считаются ресурсоёмкими. Поэтому, многие дата-сайентисты связанные с биоинформатикой, интересуются C++ (в дополнение к Python).

Важное замечание: цель этой статьи не сравнить скорость С++ и Python когда они наиболее эффективны. Код предлагаемых программ можно сделать гораздо более быстрым. Цель этой статьи — сравнить два языка, используя один и тот же алгоритм и код.

Введение в k-меры ДНК

ДНК — это длинная цепь нуклеотидов. Эти нуклеотиды могут быть четырёх типов: A, C, G и T. У вида Homo Sapiens около 3 миллиардов пар нуклеотидов. Вот небольшой кусок ДНК человека:

ACTAGGGATCATGAAGATAATGTTGGTGTTTGTATGGTTTTCAGACAATT 

Чтобы получить из него k-меры нужно разбить строку на части:

ACTA, CTAG, TAGG, AGGG, GGGA и т. д. 

Эти последовательности из четырех символов называются k-меры длина которых равна четырём (4-меры).

Задача

Мы сгенерируем всё возможные 13-меры. Математически — это перестановка с проблемой замены. Следовательно мы имеем 4 в степени 13 (67 108 864) вариантов 13-меров.

Сравнение скорости Python и С++

Мы будем использовать один и тот же алгоритм для двух языков. Код на обоих языках намеренно написан аналогично и просто. Я не использовал сложные структуры данных и сторонние библиотеки. Вот код программы на Python:

def convert(c): if (c == 'A'): return 'C' if (c == 'C'): return 'G' if (c == 'G'): return 'T' if (c == 'T'): return 'A' print("Start") opt = "ACGT" s = "" s_last = "" len_str = 13 for i in range(len_str): s += opt[0] for i in range(len_str): s_last += opt[-1] pos = 0 counter = 1 while (s != s_last): counter += 1 # Следующая строка выводит результаты # print(s) change_next = True for i in range(len_str): if (change_next): if (s[i] == opt[-1]): s = s[:i] + convert(s[i]) + s[i+1:] change_next = True else: s = s[:i] + convert(s[i]) + s[i+1:] break # Следующая строка выводит результаты # print(s) print("Number of generated k-mers: <>".format(counter)) print("Finish!") 

Выполнение этой программы займет 61.23 секунды. За это время сгенерируется 67 миллионов 13-меров. Чтобы не увеличивать время работы программы я закомментировал код выводящий результаты (25 и 37 строки). Если вы захотите запустить этот код и отобразить результаты, имейте ввиду, что это будет очень долго. Чтобы остановить выполнение программы вы можете нажать на клавиатуре CTRL+С.

Теперь посмотрим тот же алгоритм на языке C++:

#include #include using namespace std; char convert(char c) < if (c == 'A') return 'C'; if (c == 'C') return 'G'; if (c == 'G') return 'T'; if (c == 'T') return 'A'; return ' '; >int main() < cout for (int i=0; i int pos = 0; int counter = 1; while (s != s_last) < counter ++; // Следующая строка выводит результаты

На данный момент этот блок не поддерживается, но мы не забыли о нём! Наша команда уже занята его разработкой, он будет доступен в ближайшее время.

После компиляции, этот код выполнится за 2.42 секунды. Получается что Python требуется в 25 раз больше времени на эту задачу. Я повторил эксперимент с 14 и 15-мерами (это можно указать на 12 строке в Python и на 22 в C++) Теперь мы видим, что производительность этих двух языков, при выполнении одной и той же задачи, значительно различается.

Я повторюсь, обе программы далеки от идеала и могут быть значительно опимизированы. Например, мы не использовали параллельные вычисления на CPU или GPU. Но для таких задач это необходимо. Также мы не храним результаты. Хотя управление памятью в Python и C++ значительно влияет на производительность.

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

Python избавился от недостатка, над которым смеялись все программисты. Его научили работать со скоростью С и С++

Python получил сверхбыстрый компилятор. Производительность скомпилированных им программ оказалась в 10-100 раз быстрее в сравнении с приложениями на выходе традиционного интерпретатора CPython. Теперь по этому параметру Python ничуть не уступает, а в некоторых случаях даже превосходит С и C++, своих главных конкурентов среди языков программирования.

Python ускорился

Язык программирования Python, самый популярный и очень востребованный в мире, в одночасье стал в несколько раз лучше благодаря стараниям экспертов стартапа Exaloop и Массачусетского технологического института (MIT). Они создали компилятор Codon, существенно повышающий производительность скомпилированных приложений на фоне их аналогов, вышедших из-под стандартных интерпретаторов. По скорости работы они едва ли не быстрее программ на С и C++, пишет The Register.

Низкая производительность программ – то, за что Python, при всей простоте его освоения, ругают чаще всего. И нередко в этом плане его сравнивают именно с С и C++, притом не в его пользу. Codon устраняет это неравенство – по словам разработчиков, он способен генерировать на выходе чистый машинный код без привязки к среде выполнения Python Runtime.

Разработчики уверяют, что в сравнении с обычными интерпретаторами для Python новый Codon обеспечивает ПО в 10-100 раз более высокую производительность. В данном случае идет сравнение с интерпретатором CPython при в однопоточном режиме работы. «Производительность Codon обычно соответствует (а иногда и лучше) производительности компиляторов C/C++», – утверждают они.

Все бесплатно, но не совсем

Проект Codon распространяется по лицензии Business Source License (BSL), то есть по умолчанию все его компоненты доступны бесплатно при соблюдении ряда условий эксплуатации. Все без исключения файлы, необходимые для работы Codon, размещены в профиле стартапа Exaloop на GitHub (принадлежит Microsoft). В комплект входят компилятор, среда выполнения (runtime) для исполняемых файлов и отдельная библиотека функций на замену штатным библиотечным вызовам на Python.

pyn600.jpg

Python получил еще одно неоспоримое преимущество

Что немаловажно, исходные тексты самого компилятора, библиотеки и runtime написаны вовсе не на Python, как многие, вероятно, ожидали. Авторы использовали C++.

Ограничения, накладываемые лицензией BSL на бесплатное использование распространяемого под ней ПО, всегда имеют срок действия. В случае с Codon они продлялся до 1 ноября 2025 г., после чего весь проект будет переведен на лицензию Apache 2.0. А пока Codon распространяется под BSL, его код можно копировать и модифицировать, если в дальнейшем он не будет использоваться в коммерческих целях.

Плюсов без минусов не бывает

Codon разрабатывается как фреймворк для создания высокопроизводительных предметно-ориентированных языков (DSL) в Python. DSL — это языки, ориентированные на конкретную цель, в отличие от языка программирования общего назначения, которым относятся, например, Python или C. Примеры DSL – это CSS и SQL.

У истоков проекта стоят создатели Python-подобного языка программирования Seq, который и лежит в его основе. Авторы Codon позиционируют его как наследника Seq.

Умный ответ на новые вызовы: как искусственный интеллект помогает ритейлерам и FMCG-компаниям решать проблемы с конкуренцией и логистикой

К недостаткам Codon эксперты The Register относят в первую очередь выбор разработчиками лицензии BSL с ее ограничениями, и необходимость ждать два с половиной года до перехода на Apache 2.0. Также они упомянули отсутствие поддержки некоторых модулей Python. Например, компилятор пока не поддерживает функции динамической обработки типов, плюс для целых чисел в нем используется только 64-битный тип int. В CPython таких ограничений нет.

Плюсы Codon – это очень высокая производительность при однопоточном выполнении. Компилятор также снабжен возможностью работы в многопоточном режиме.

Почему именно C++

Python – это самый популярный язык программирования в мире, согласно рейтингу Tiobe. На первое место в нем он вырвался лишь в октябре 2021 г., хотя существует Python c середины 1980-х годов. Его популярность стремительно растет лишь в последние несколько лет, тогда как другие представители топ-3 Tiobe находятся на вершине этого рейтинга годами.

Основной конкурент Python – это С, с компилятором для которого авторы Codon сравнили свое детище в первую очередь. До октября 2021 г. именно он был первым в рейтинге Tiobe. В декабре 2022 г. в тройку лидеров, сместив Java, вошел C++ – еще один конкурент Python. Скорость компиляции всегда была их неоспоримым преимуществом перед Python, которого, благодаря Codon, больше нет.

Почему С++ быстрее многих языков программирования?

Достаточно интересно полностью понять, почему С++ настолько быстр по сравнению с условным Kotlin, Java или C#. Вопрос: Расскажите пожалуйста в деталях, почему именно так) Предполагаю, что это благодаря достаточно гибкой работой с памятью, но кажется, что сильно заблуждаюсь)

Отслеживать
задан 6 мая в 14:41
118 2 2 серебряных знака 15 15 бронзовых знаков

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

6 мая в 14:43
6 мая в 14:53
@aleksandrbarakin тут вопрос не про Python
6 мая в 14:53
@andreymal, какая разница? ответы там есть и они полностью покрывают смысл данного вопроса.
6 мая в 14:54

@aleksandrbarakin целых три принципиальных разницы: в питоне (подразумеваю CPython) есть GIL, нет статической типизации и нет JIT-компиляации — а в Java и C# всё ровно наоборот

6 мая в 14:56

3 ответа 3

Сортировка: Сброс на вариант по умолчанию

Во, я наверное хорошо смогу ответить, так как являюсь специалистом в C# и .NET

Но перед тем как вникать в суть, запомните основное правило: тормозит не язык, на котором вы написали код или среда выполнения, тормозит сам код, который вы написали.

И главная проблема плохого тормозящего кода в таких средах со сборщиком мусора, как .NET и Java, это отсутствие экспертизы в области поведения той самой машины управления памятью. Хочешь создать 200кк массивов для выполнения задачи - легко, код прост. Просто спавни объекты и ни о чем не думай, а сборщик мусора разберется.

В таких средах, где нет встроенного управления памятью, и надо его писать по большей части самому, приходится разбираться с этим до того как код дописать, потому что иначе будут утечки и прочие неприятности. Когда учишь С++, изначально познаешь базовые тонкости работы с памятью, а многие новички сразу начинают различать malloc и calloc , и осознавать, что выделение высвобождение памяти не бесплатно по времени и требует работы, переиспользуют память и т.д.

Чтобы научиться контролю аллокаций в средах типа .NET, требуется сначала написать много тормознутого кода, и наконец-то встретиться с проблемой низкой производительности или перерасхода памяти лицом к лицу. То есть вникание в управление памятью и суть работы сборщика происходит гораздо позднее. Поэтому при одинаковом объеме обучающих материалов, специалист по C++ узнает про нюансы производительности раньше, чем специалист по C#. И это нормально, это специфика среды, в которой работает код.

Поэтому вопрос "что быстрее, С++ или C#/Java" изначально не имеет смысла. Даже если столкнуть лбами двух супермегаэкспертов C++ и C# - неизвестно, чей код будет быстрее. Напишешь на C++ код, потом начнешь тестировать, на одном сервере победишь C#, на другом в другой архитектуре - проиграешь. Ну потому что JIT во время компиляции знает все тонкости процессора, выполняющего код, а компилятор C++ - не знает, он знает только архитектуру. Есть еще PGO (Profile-Guided Optimization) в CLR (Common Language Runtime/.NET) - великолепная шутка, которая может перекомпилировать с сильными оптимизациями код уже запущенного приложения в зависимости от интенсивности использования некоторых методов в коде (речь про последние версии .NET, но раньше ситуация была хуже). В C++ такого либо нет, либо оно достигается значительно тяжелее, чем в среде с JIT. И еще миллионы нюансов, которые никак не ответят на ваш вопрос однозначно.

И здесь можно повторить вывод, который написан жирным шрифтом выше, в самом начале. А утверждение "С++ быстрее многих языков программирования" по факту не соответствует действительности. Я могу на C# написать код, который будет например применять фильтр к Full HD картинке 2 секунды, а могу потом переписать его так, что станет потом 4мс, а качество машинного кода, который выдает JIT, будет не сильно хуже, чем генерит gcc/clang. Не забывайте, что компиляция байт-кода (или CIL) производится машиной в целом однократно, а затем уже работает только скомпилированная версия. Например вызываете какой-то метод 1000 раз, а компилироваться он будет только однажды. JIT - это не интерпритатор байт-кода, а компилятор.

Почему код на Python работает быстрее в функции?

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

def example(): for i in range(10**8): pass example()

Вышеуказанный код может работать быстрее, чем следующий:

for i in range(10**8): pass

Почему это происходит?

Прежде всего, стоит уточнить, что Python — это интерпретируемый язык программирования. Это означает, что каждая строка кода исполняется поочередно. При этом интерпретатор Python использует специальные объекты для представления различных элементов кода, таких как функции, циклы и так далее.

Когда Python исполняет код внутри функции, он создает специальный объект функции, который содержит весь код этой функции. Если код функции не изменяется, то Python может кешировать этот объект и использовать его при каждом вызове функции. Это может существенно ускорить исполнение кода.

В случае с кодом, который не обернут в функцию, Python должен каждый раз заново создавать объекты для каждой строки кода. Это занимает больше времени и ресурсов, что приводит к медленной работе кода.

Кроме того, Python имеет оптимизации для локальных переменных внутри функций. Эти оптимизации делают доступ к локальным переменным быстрее, чем к глобальным.

В заключение можно сказать, что использование функций в Python не только помогает делать код более структурированным и понятным, но и может ускорить его работу.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *