Статья:

Производительность языка программирования Python

Конференция: XXVII Студенческая международная научно-практическая конференция «Технические и математические науки. Студенческий научный форум»

Секция: Физико-математические науки

Выходные данные
Пасюта М.А., Комаров А.В. Производительность языка программирования Python // Технические и математические науки. Студенческий научный форум: электр. сб. ст. по мат. XXVII междунар. студ. науч.-практ. конф. № 4(27). URL: https://nauchforum.ru/archive/SNF_tech/4(27).pdf (дата обращения: 27.12.2024)
Лауреаты определены. Конференция завершена
Эта статья набрала 0 голосов
Мне нравится
Дипломы
лауреатов
Сертификаты
участников
Дипломы
лауреатов
Сертификаты
участников
на печатьскачать .pdfподелиться

Производительность языка программирования Python

Пасюта Максим Андреевич
студент, Алтайский государственный технический университет им. И.И. Ползунова, РФ, г. Барнаул
Комаров Андрей Владимирович
студент, Алтайский государственный технический университет им. И.И. Ползунова, РФ, г. Барнаул

 

Python – универсальный язык программирования, на котором можно создавать проекты под любые платформы. Создавайте веб-приложения, занимайтесь анализом данных, автоматизируйте задачи управления системами и многое другое. В данной статье рассматривается реализация интерпретатора CPython [1]. По мнению многих разработчиков, проекты Python работают во много раз медленнее, чем аналогичные программные решения на других языках. Попытаемся разобраться в этом. Рассмотрим основные особенности языка программирования Python, которые могут повлиять на скорость работы программы:

• Работа блокировки потоков GIL (Global Interpreter Lock, глобальная блокировка интерпретатора) [1].

• Python - интерпретирующий, а не компилируемый язык [3].

• Python - это язык с динамической типизацией [2].

Сначала поговорим о том, что такое GIL (Global Interpreter Lock). GIL тесно связан с функционированием потока. Современные компьютеры имеют многоядерные процессоры, а иногда даже являются многопроцессорными системами. Чтобы использовать все эти вычислительные мощности, операционная система использует низкоуровневые структуры, называемые потоками и процессами (процесс программы MATLAB), которые могут запускать несколько потоков и использовать их соответствующим образом. В результате, например, если конкретному процессу требуется много ресурсов процессора, его выполнение может быть распределено на несколько ядер. Благодаря этому методу у большинства приложений возрастает производительность при выполнении программы. Блокировки используются для многопоточных приложений. Ключевым является то, что они позволяют такой системе защищать память при одновременном обращении двух потоков (чтение или запись) к одной ячейке. В Python именно GIL занимается защитой памяти интерпретатора от разрушений. Реализует данную задачу он при помощи деления всех операций с памятью на атомарные.

Python - это интерпретируемый язык программирования. Часто приходится слышать, что низкая производительность Python связана с особенностью сборки проектов. Подобные утверждения основаны на грубом упрощении того, как, на самом деле, работает CPython. Если запустить любую программу с расширение .py, CPython начнёт длительную последовательность действий, которая заключается в чтении, лексическом анализе, парсинге, компиляции, интерпретации и выполнении кода скрипта. В качестве примера рассмотрим простейшую функцию умножения, которая будет принимать в качестве параметров 2 числа и возвращать их произведение. Функция, как и всё в Python, является объектом, и сделав её импорт, мы можем перечислить её методы с помощью функции dir(). Один из атрибутов функции -  это __code__, в котором содержится code object - объект, который оборачивает написанный код. У этого объекта есть метод co_code, который возвращает байткод, сгенерированный Python для этой функции (то есть инструкции для интерпретатора Python). Чтобы привести байткод в читаемый вид (т.е. дизассемблировать), используется функция dis.dis() из пакета dis.

 

Рисунок 1. Выполнение команды dis.dis(multiply)

 

Это касается не только скриптов, которые мы пишем, но и импортированного кода сторонних модулей. В результате большую часть времени (если вы не пишите код, который выполняется только один раз), Python занимается выполнением готового байт-кода. На рисунке - 1 мы видим, что функция преобразуется в цикл из четырех инструкций. Каждая из этих инструкций содержит определенное действие. Первым является LOAD_FAST, который изменяет содержимое переменной в памяти и помещает ее в стек. Когда переменная ‘a’ помещается в стек, мы переключаемся на аналогичную команду для переменной ‘b’. Следующая инструкция, BINARY_MULTIPLY, говорит интерпретатору Python взять два верхних значения в стеке и умножить их. Обратите внимание, что мы можем передать значение любого типа в функцию: целое число, действительное число или строку, этот байт-код не меняет этого. Типизация объекта начинается, когда Python выполняет инструкцию. В этом случае, когда выполняется оператор BINARY_MULTIPLY, Python просматривает тип объекта и, например, если это два целых числа, умножает два целых числа. Далее результат умножения помещается на вершину стека. И последний оператор RETURN_VALUE, который возвращает переменную из верхней части стека. Это касается не только скриптов, которые мы пишем, но и импортированного кода сторонних модулей. В результате большую часть времени (если вы не напишите код, который выполняется только один раз) Python занимается выполнением готового байт-кода.

Python - это динамически типизированный язык программирования. В отличии от языков со статической типизацией, Python не нуждается в объявлении типа переменной при ее создании. Так же к языкам с динамической типизацией относят Objective-CRubyPHPPerlJavaScript. В данных языках программирования понятие типов данных имеет то же значение что и в классическом С, но тип переменной является динамическим. Реализуется данный механизм следующим образом. Типы переменных неизвестны до того момента, когда у них есть конкретные значения при запуске. Проверка типов и их преобразование являются сложными операциями. Каждый раз, когда к переменной обращаются, читают или записывают значение, выполняется проверка типа. Из-за чего существенно страдает скорость работы приложений.

В качестве вывода хочется отметить, что причиной низкой производительности Python является его динамическая составляющая, а также универсальность. Изначально математиком Гвидо ван Россум этоn язык программирования был задуман как простой и выразительный язык. Создатель Python хотел представить всему миру универсальный инструмент, который позволит избежать сложных структур кодирования. Он хотел реализовать язык программирования, в котором код программы будет читаться, как обычный английский язык.

 

Список литературы:
1. Как устроен GIL в Python [Электронный ресурс]. – Электрон. дан. – Заглавие с экрана. – Режим доступа: URL: https://habr.com/ru/post/84629/ (дата обращения: 15.03.2020).
2. Статическая и динамическая типизация [Электронный ресурс]. – Электрон. дан. – Заглавие с экрана. – Режим доступа: URL: https://habr.com/ru/post/308484/ (дата обращения: 15.03.2020).
3. Основные принципы программирования: компилируемые и интерпретируемые языки [Электронный ресурс]. – Электрон. дан. – Заглавие с экрана. – Режим доступа: URL: https://tproger.ru/translations/programming-concepts-compilation-vs-interpretation/ (дата обращения: 15.03.2020).