Вышел Python 3.12, в котором появились суб-интерпретаторы

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

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

Внедрение подинтерпретаторов с GIL для каждого интерпретатора может сделать спорным вопрос об удалении GIL. Чтобы понять, что происходит, необходимо осознать, что проблема с GIL, Global Interpreter Lock, заключается именно в этом - в блокировке интерпретатора Python. Это означает, что в любой момент времени интерпретатор Python может выполняться только одним потоком. Таким образом, даже если у вас есть 100 ядер для работы, и вы используете потоки Python, ваша программа на Python выполняет только одну инструкцию за раз. Фактически это делает идею потоков Python полезной только для потоков, связанных с вводом-выводом. В этом случае у вас может быть N потоков, и пока N-1 из них ждут, пока что-то произойдет, все будет работать настолько эффективно, насколько это вообще возможно.

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

Есть и второе, менее очевидное решение - сохранить GIL, просто поставить больше интерпретаторов. Это идея суб-интерпретатора, и вы уже можете использовать эту идею, но только если вы используете процессы Python, а не потоки Python. Если вы создаете новый процесс Python, то получаете новый процесс операционной системы, изолированный от исходной программы. Он может выполнять Python, не заботясь о GIL, поскольку в процессе установлен свой собственный интерпретатор Python, а у этого интерпретатора есть свой собственный GIL. При таком подходе, если у вас есть 100 ядер, вы можете иметь 100 частей ваших Python-программ, выполняющихся одновременно - но каждая из них в любой момент времени выполняет только один поток.

Конечно, недостатком такого подхода является загрузка 100 копий интерпретатора Python и, следовательно, нерациональное использование памяти - но память стоит дешево. Гораздо более серьезной проблемой является то, что каждый интерпретатор закрыт внутри блока процессов, что затрудняет и замедляет передачу данных между ними. Преимущество потоков заключается в том, что они естественным образом разделяют одно и то же пространство процесса и, следовательно, имеют доступ к одним и тем же глобальным файлам. Но и здесь есть проблема: необходимо контролировать доступ к общим переменным, а это обычно означает блокировку. Межпроцессное взаимодействие обычно осуществляется с помощью труб или аналогичных объектов, которые часто не нуждаются в блокировке.

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

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

Все это звучит революционно - мы можем делать программы на Python быстрее и при этом полагаться на GIL, который убережет нас от неприятностей. Это действительно так, но в Python 3.12 добавлено не все, что нужно. В частности, вы можете использовать только подинтерпретаторы из C API. Это означает, что вы можете написать расширение для языка C, загрузить в него подинтерпретаторы и использовать их для выполнения программ на Python, а затем, предположительно, использовать C для сбора результатов. Это интересно, но вряд ли повлияет на рядового программиста Python. В лучшем случае это позволит авторам расширений на Си ускорить свои творения.

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

Таким образом, революция должна произойти в Python 3.13, когда нам также обещают отказ от GIL. Что произойдет и что окажется практичным?

Жизнь без GIL или жизнь с несколькими GIL - это мы узнаем только в версии 3.13.

Вышел Python 3.12, в котором появились суб-интерпретаторы
Понравилась новость? Тогда не забудь оставить свой комментарий.
А так же, добавь наш сайт в закладки (нажми Ctrl+D), не теряй нас.
06 октября 2023 г.
161

Комментарии

Оставить комментарий:
* отправляя форму, я даю согласие на обработку персональных данных

Читайте еще