先日投稿した記事 Pythonの計算を早くするには の内容についてPythonのコードがC言語に比べて大分遅かった為、改善策はあるのか検証します。
最初のコード
wallis_v2.py
from numpy import *
def f(x):
return sin(pi*x)
product_array = [0 for i in range(10)]
n = 1000000
inv_n = 1.0 / n
for k in range(n):
x = k * inv_n
y = f(x)
z = y
for m in range(10):
product_array[m] += z
z *= y
product = prod(list(map(lambda x: x * inv_n, product_array)))
result = 1.0/product
print(result)
初回の実行時に最適化が動くようなので、2回目以降の値を参考にします。
$ time python3 wallis_v2.py
36722.3621743
python3 wallis_v2.py 8.96s user 0.05s system 99% cpu 9.050 total
importの最適化
まずimport
の部分を使用するモジュールに限定します。
from numpy import prod
from math import sin, pi
$ time python3 wallis_v2.py
36722.3621743
python3 wallis_v2.py 7.67s user 0.06s system 99% cpu 7.755 total
1秒以上早くなりました。
Cythonの使用
pyxファイルへの分割
次にCythonを導入します。その為に処理自体をpyxファイルに分割します。
wallis_v3.py
import pyximport
pyximport.install()
from integral_lib import integral
print(integral(1000000))
integral_lib.pyx
from numpy import prod
from f import f
def integral(n):
product_array = [0 for i in range(10)]
inv_n = 1.0 / n
for k in range(n):
x = k * inv_n
y = f(x)
z = y
for m in range(10):
product_array[m] += z
z *= y
return 1 / prod(list(map(lambda x: x * inv_n, product_array)))
f.pyx
from math import sin, pi
def f(x):
return sin(pi * x)
$ time python3 wallis_v3.py
36722.3621743
python3 wallis_v3.py 1.05s user 0.06s system 98% cpu 1.134 total
大分早くなりました。
静的型付
f2.pyx
from math import sin, pi
def f(double x):
cdef:
double res = sin(pi * x)
return res
integral_lib2.pyx
from numpy import prod
from f2 import f
def integral(int n):
product_array = [0.0 for i in range(10)]
cdef:
double inv_n = 1.0 / n
double x,y,z
int k
for k in range(n):
x = k * inv_n
y = f(x)
z = y
for m in range(10):
product_array[m] += z
z *= y
return 1.0 / prod(list(map(lambda x: x * inv_n, product_array)))
wallis_v3.py
from integral_lib2 import integral
$ time python3 wallis_v3.py
36722.3621743
python3 wallis_v3.py 0.80s user 0.06s system 97% cpu 0.884 total
早くできました。
参考にした記事中にlibcを呼び出す方法が紹介されていたので試して見ました。一応早くなっています。
f2.pyx
from libc.math cimport sin,M_PI
def f(double x):
cdef:
double res = sin(M_PI * x)
return res
$ time python3 wallis_v3.py
36722.3621743
python3 wallis_v3.py 0.72s user 0.06s system 97% cpu 0.802 total
初期のコードでは22秒だったものが、0.8秒ほどまで高速化することはできましたが、コードの保守性などを考えるとこれがベストと云うわけではありませんので、適宜選んでください。