Pythonが遅い理由とその対策

## はじめに

Pythonは柔軟性が高く、初心者にも適したプログラミング言語ですが、その一方で速度面では他の言語に劣るとされています。本記事では、先月ピッツバーグで開催されたPyCon US 2024で紹介されたPythonの高速化技術について詳しく解説します。

## Pythonの速度問題

「Pythonはランタイムにコストを払う」という古い格言が示す通り、Pythonは解釈型言語であり、実行時に多くの処理を行うため速度が遅くなることがあります。Pythonはソースコードを効率的なバイトコードに変換し、それを直接実行することで動作します。このプロセスには多くの間接処理が含まれ、単純な命令でさえも多数のCPU指示に分解されます。例えば、二つの数値を足すだけでも500以上の命令が実行されることがあります。

## 高速化のためのコンパイル技術

### Cythonによる最適化

PyCon 2024でのSaksham Sharma氏の発表では、Cythonを用いた高速化手法が紹介されました。CythonはPythonコードをC言語にコンパイルすることで、実行速度を大幅に向上させることができます。Sharma氏は、取引システムを構築する際にC++を使用しており、そのスピードをPythonにも取り入れたいと考えています。

Cythonを使うことで、Pythonコードは以下のように変換されます。

```python
def print_add(a, b):
    c = a + b
    print(c)
    return c
```

このPythonコードがCythonでは次のようになります。

```c
PyObject *__pyx_pf_14cython_binding_print_add(...) {
    ...
    __Pyx_XDECREF(__pyx_r);
    __Pyx_INCREF(__pyx_v_c);
    __pyx_r = __pyx_v_c;
    goto _pyx_L0;
    ...
}
```

Sharma氏の実験では、Pythonでの処理に70ナノ秒かかるところが、Cythonでは約14ナノ秒に短縮されました。これは、インタプリタによる型チェックなどの間接処理を省略できるためです。

### SPy：静的型付けPython

AnacondaのAntonio Cuni氏は、SPyという新しい静的型付けを必要とするPythonのサブセットを紹介しました。SPyの目標は、CやC++のスピードを持ちながら、Pythonの使いやすさを維持することです。SPyでは、すべてのグローバル定数が不変として固定され、JITコンパイラによって最適化されます。

Cuni氏は、Pythonが命令を実行する前に多くの準備作業を行う必要があることを指摘しました。SPyでは、この準備作業の多くをコンパイル段階で行うため、実行速度が向上します。現在、Cuni氏はSPyをCPythonの拡張として、または独自のJITコンパイラとして実装することに取り組んでいます。

## C拡張モジュールの静的リンク

MetaのエンジニアリングマネージャーであるLoren Arthur氏は、C拡張モジュールを使用してPythonの速度を向上させる方法について説明しました。Metaでは、PythonコードをCで書き直すことで、大量のデータ処理を4秒から0.5秒に短縮することができました。

しかし、C拡張モジュールの動的リンクには問題があり、多数のモジュールを含むとインポート時間が増加します。Metaでは、C拡張モジュールを静的にリンクすることで、この問題を解決しました。静的リンクにより、Cコードが直接実行ファイルに埋め込まれるため、インポート時間が短縮されます。

## 不死オブジェクトの導入

Azion TechnologiesのソフトウェアエンジニアチームリーダーであるVinícius Gubiani Ferreira氏は、不死オブジェクトの導入について説明しました。Pythonのグローバルインタプリタロック（GIL）は、複数のプロセスが同時にPythonコードを実行することを防ぐために設計されましたが、マルチコア並列計算を妨げる要因ともなっています。

Ferreira氏の発表によると、不死オブジェクトは参照カウントが変わらないオブジェクトであり、これによりGILを回避してマルチスレッドでの同時実行が可能になります。この手法により、特にマルチプロセッサ環境でのパフォーマンスが向上します。

## サブインタプリタの活用

PythonのコアデベロッパーでありEdgeDBのCEOであるYury Selivanov氏は、サブインタプリタを活用することでGILを回避する方法について紹介しました。サブインタプリタは、同じメモリ空間を共有しながら、それぞれ独自のGILを持つ複数のインタプリタを作成することができます。

Selivanov氏の作成したmemhiveフレームワークは、サブインタプリタのワーカープールを実装し、データ共有のためのRPCメカニズムを提供します。これにより、複数のサブインタプリタが同時に同じデータセットを操作することが可能になります。これにより、処理速度が6倍から150,000倍に向上することが確認されています。

## まとめ

本記事では、PyCon 2024で紹介されたPythonの高速化技術について詳しく解説しました。Pythonはその柔軟性と使いやすさから広く利用されていますが、速度面での課題があります。しかし、CythonやSPy、静的リンク、不死オブジェクト、サブインタプリタなどの新しい技術が導入されることで、Pythonの実行速度が大幅に向上する可能性があります。これらの技術を活用することで、Pythonを使用した高性能なアプリケーション開発がさらに進むことが期待されます。

人気記事です

https://qiita.com/wooooo/items/24d1a4d6be5ab7bf023f
## 参考文献

- [PyCon US 2024 公式サイト](https://us.pycon.org/2024/)

https://thenewstack.io/why-python-is-so-slow-and-what-is-being-done-about-it/

---

## Introduction

Python is known for its flexibility and suitability for beginners, but it is often considered slower compared to other programming languages. In this post, I will explain the techniques introduced at PyCon US 2024 in Pittsburgh to improve Python's performance.

## The Issue with Python's Speed

As the old saying goes, "Python pays the cost at runtime." Python is an interpreted language, meaning that it executes many operations during runtime, which can lead to slower speeds. Python translates source code into efficient bytecode and then directly executes it. However, this process involves a lot of indirect operations, and even simple commands can be broken down into hundreds of CPU instructions. For example, adding two numbers might take over 500 instructions.

## Compilation Techniques for Speed Optimization

### Optimization with Cython

Saksham Sharma's presentation at PyCon 2024 introduced the use of Cython to optimize Python's speed. Cython compiles Python code into C language, significantly improving execution speed. Sharma, who uses C++ in building trading systems, aimed to bring the speed of C++ to Python.

Here’s a Python example:

```python
def print_add(a, b):
    c = a + b
    print(c)
    return c
```

In Cython, it would be transformed as follows:

```c
PyObject *__pyx_pf_14cython_binding_print_add(...) {
    ...
    __Pyx_XDECREF(__pyx_r);
    __Pyx_INCREF(__pyx_v_c);
    __pyx_r = __pyx_v_c;
    goto _pyx_L0;
    ...
}
```

In Sharma's experiment, an operation that took 70 nanoseconds in Python was reduced to 14 nanoseconds in Cython due to the elimination of indirect overhead like type checks.

### SPy: Statically-Typed Python

Antonio Cuni from Anaconda introduced SPy, a new subset of Python that requires static typing. The goal of SPy is to achieve the speed of C or C++ while maintaining Python’s ease of use. SPy treats all global constants as immutable, allowing for optimization through a JIT compiler.

Cuni pointed out that Python performs a lot of preparatory work before executing instructions. SPy eliminates much of this work at compile time, thus improving execution speed. Cuni is currently working on implementing SPy as an extension of CPython or as a separate JIT compiler.

## Static Linking of C Extension Modules

Loren Arthur, Engineering Manager at Meta, discussed how to speed up Python using C extension modules. Meta was able to reduce large-scale data processing from 4 seconds to 0.5 seconds by rewriting Python code in C.

However, the dynamic linking of C extension modules can increase import times when many modules are involved. Meta solved this issue by statically linking C extension modules, embedding the C code directly into the executable, thus reducing import times.

## Introduction of Immortal Objects

Vinícius Gubiani Ferreira, Team Lead at Azion Technologies, discussed the concept of "immortal objects." Python's Global Interpreter Lock (GIL) prevents multiple processes from executing Python code concurrently, which hinders multi-core parallel computation.

According to Ferreira, immortal objects have a reference count that never changes, allowing them to bypass the GIL and enabling multi-threaded execution. This technique improves performance, especially in multi-processor environments.

## Utilizing Subinterpreters

Yury Selivanov, a core Python developer and CEO of EdgeDB, introduced subinterpreters as a way to avoid the GIL. Subinterpreters create multiple interpreters that each have their own GIL but share the same memory space.

Selivanov's memhive framework implements a worker pool using subinterpreters and provides an RPC mechanism for data sharing. This allows multiple subinterpreters to operate on the same dataset simultaneously, achieving speed improvements ranging from 6x to 150,000x.

## Conclusion

This article has detailed the Python optimization techniques introduced at PyCon 2024. While Python is widely used due to its flexibility and ease of use, it has faced challenges in terms of speed. However, new techniques like Cython, SPy, static linking, immortal objects, and subinterpreters have the potential to dramatically improve Python's execution speed. Leveraging these technologies will advance high-performance application development using Python.

For popular articles, visit:  [Popular Blog Post](https://qiita.com/wooooo/items/24d1a4d6be5ab7bf023f)

## References

- [PyCon US 2024 Official Site](https://us.pycon.org/2024/)
- [Why Python Is So Slow and What Is Being Done About It](https://thenewstack.io/why-python-is-so-slow-and-what-is-being-done-about-it/)