M.Hiroi's Home Page

Lightweight Language

お気楽 Python3 プログラミング超入門

[ Home | Light | Python3 ]

●Python の高速化

Python は使いやすいプログラミング言語ですが、実行速度はお世辞にも速いとは言えません。時間がかかる処理をC言語で記述してライブラリを作成し、それをインポートして呼び出す方法もありますが、Python のプログラムを変更なして高速化できるならば、その方が簡単で便利です。今回は Python のプログラムを高速化する簡単な方法を 2 つ紹介します。

●PyPy

Python は Guido van Rossum 氏がC言語で作成した処理系 (CPython) が標準ですが、これ以外にもいくつか処理系があります。その中で JIT コンパイル機能を持つ PyPy は CPython の数倍速いといわれています。

PyPy は上記公式サイトからダウンロードすることができます。また、少し古いバージョンになりますが、Ubuntu 20.04 LTS の場合、次のコマンドでインストールすることができます。

$ sudo apt install pypy3
$ pypy3 --version
Python 3.6.9 (7.3.1+dfsg-4, Apr 22 2020, 05:15:29)
[PyPy 7.3.1 with GCC 9.3.0]

PyPy はどのくらい速いのか、たらいまわし関数を使って調べてみました。プログラムは次のようになります。

リスト : たらいまわし関数 (tarai.py)

import time

def tarai(x, y, z):
    if x <= y: return y
    return tarai(tarai(x - 1, y, z), tarai(y - 1, z, x), tarai(z - 1, x, y))

def tak(x, y, z):
    if x <= y: return z
    return tak(tak(x - 1, y, z), tak(y - 1, z, x), tak(z - 1, x, y))

def test(func, x, y, z):
    s = time.time()
    print(func(x, y, z))
    e = time.time()
    print(e - s)

それでは実行結果を示します。実行環境は Ubuntu 20.04 LTS (WSL1), Intel Core i5-6200U 2.30GHz です。

$ python3
Python 3.8.10 (default, Jun 22 2022, 20:18:18)
[GCC 9.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from tarai import *
>>> test(tarai, 14, 7, 0)
14
56.31682109832764
>>> test(tak, 22, 11, 0)
11
61.39163279533386
$ pypy3
Python 3.6.9 (7.3.1+dfsg-4, Apr 22 2020, 05:15:29)
[PyPy 7.3.1 with GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>> from tarai import *
>>>> test(tarai, 14, 7, 0)
14
17.607698678970337
>>>> test(tak, 22, 11, 0)
11
21.849809169769287

PyPy の実行速度は CPython の約 3 倍になりました。プログラムによってはもっと速くなる場合もあるでしょうし、逆に遅くなる場合もあるかもしれません。たとえば、フィボナッチ関数の実行速度は次のようになりました。

リスト : フィボナッチ関数 (tarai.py に追加)

def fibo(n):
    if n < 2:
        return n
    else:
        return fibo(n - 1) + fibo(n - 2)

 def testfibo(n):
    s = time.time()
    print(fibo(n))
    e = time.time()
    print(e - s)
$ python3
Python 3.8.10 (default, Jun 22 2022, 20:18:18)
[GCC 9.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from tarai import *
>>> testfibo(38)
39088169
11.766613960266113
$ pypy3
Python 3.6.9 (7.3.1+dfsg-4, Apr 22 2020, 05:15:29)
[PyPy 7.3.1 with GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>> from tarai import *
>>>> testfibo(38)
39088169
1.1087980270385742

最新の PyPy を使うともう少し速くなるかもしれません。興味のある方はいろいろ試してみてください。

●Numba

PyPy のほかにも、Python のプログラムを JIT コンパイルする方法があります。ライブラリ Numba をインポートすると Python に JIT コンパイラを導入することができます。

Numba のインストールは pip を使うと簡単です。pip は Python で書かれたパッケージ管理ツールです。次のコマンドで pip がインストールされているか確認することができます。

$ python3 -m pip -V
/usr/bin/python3: No module named pip

pip が入っていない場合は、次のコマンドでインストールしてください。

sudo apt install python3-pip

あとは pip で Numba をインストールするだけです。

$ pip3 install numba

Numba の基本的な使い方は簡単で、高速化したい関数の前に @jit を付けるだけです。これでその関数が JIT コンパイルされます。それでは、たらいまわし関数で実行時間を計測してみましょう。

リスト : たらいまわし関数

from numba import jit
import time

@jit
def tarai(x, y, z):
    if x <= y: return y
    return tarai(tarai(x - 1, y, z), tarai(y - 1, z, x), tarai(z - 1, x, y))
@jit
def tak(x, y, z):
    if x <= y: return z
    return tak(tak(x - 1, y, z), tak(y - 1, z, x), tak(z - 1, x, y))

@jit
def fibo(n):
    if n < 2:
        return n
    else:
        return fibo(n - 1) + fibo(n - 2)

def test(func, x, y, z):
    s = time.time()
    print(func(x, y, z))
    e = time.time()
    print(e - s)

def testfibo(n):
    s = time.time()
    print(fibo(n))
    e = time.time()
    print(e - s)
$ python3
Python 3.8.10 (default, Jun 22 2022, 20:18:18)
[GCC 9.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from tarai import *
>>> test(tarai, 14, 7, 0)
14
3.2922072410583496
>>> test(tarai, 14, 7, 0)
14
2.9705183506011963
>>> test(tarai, 14, 7, 0)
14
2.9666898250579834
>>> test(tak, 22, 11, 0)
11
3.4130196571350098
>>> test(tak, 22, 11, 0)
11
3.277550220489502
>>> test(tak, 22, 11, 0)
11
3.268494129180908
>>> testfibo(38)
39088169
0.545701265335083
>>> testfibo(38)
39088169
0.4606921672821045
>>> testfibo(38)
39088169
0.46005892753601074

実行環境 : Ubuntu 20.04 LTS (WSL1), Intel Core i5-6200U 2.30GHz

素の Python3 では tak(22, 11, 0) に 61.4 秒、PyPy3 では 21.8 秒かかりますが、Numba を使用することで 3.3 秒に短縮することができました。初回の実行にはちょっと時間がかかりますが、2 回目以降はどの関数も高速に実行することができました。

JIT コンパイラを使ったスクリプト言語では Julia が速いのですが、たらいまわし関数を実行すると約 2 秒ほどかかります。Julia に迫る速度を叩き出すのですから、Numba の JIT コンパイラは優秀ですね。Python のプログラムを高速化するときには試してみたいツールだと思ました。


Copyright (C) 2022 Makoto Hiroi
All rights reserved.

[ Home | Light | Python3 ]