Я использую MingW64 для компиляции Cython для Python 3.7. Задача представляет собой исключение, когда я вычисляю набор Джулии для сетки точек. Я слежу за книгой «High Performance Python», в которой рассказывается, как использовать Cython. Я ранее использовал флаг -O для настройки оптимизации для оборудования DSP и получил значительные улучшения, установив его выше, например -O3. Однако это не относится к коду Cython.
При выполнении того же самого с кодом Cython он стабильно дает более медленные результаты по мере увеличения оптимизации, что, кажется, не имеет смысла. Я получаю следующие тайминги:
-O1 = 0,41 с
-O2 = 0,46 с
-O3 = 0,47 с
-Ofast = 0,48 с
-Os = 0,419 с
У кого-нибудь есть идея, почему это, похоже, работает при противоположных оптимизациях?
Код cython находится в файле cythonfn.pyx
def calculate_z(maxiter, zs, cs):
# add type primitives to improve execution time
cdef unsigned int i, n
cdef double complex z, c
output = [0] * len(zs)
for i in range(len(zs)):
n = 0
z = zs[i]
c = cs
# while n < maxiter and abs(z) < 2:
while n < maxiter and (z.real * z.real + z.imag * z.imag) < 4: # increases performance
z = z * z + c
n += 1
output[i] = n
return output
Настройка здесь как setup.py
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
setup(
cmdclass={'build_ext': build_ext},
ext_modules=[Extension("calculate", ["cythonfn.pyx"])]
)
И основной код -
import calculate
import time
c_real,c_imag = -0.62772, -0.42193 # point for investigation
x1, x2, y1, y2 = -1.8, 1.8, -1.8, 1.8
def calc_julia(desired_width, max_iter):
x_step = (float(x2 - x1) / float(desired_width))
y_step = (float(y1 - y2) / float(desired_width))
x = []
y = []
ycoord = y2
while ycoord > y1:
y.append(ycoord)
ycoord += y_step
xcoord = x1
while xcoord < x2:
x.append(xcoord)
xcoord += x_step
zs = []
cs = complex(c_real, c_imag)
for ycoord in y:
for xcoord in x:
zs.append(complex(xcoord, ycoord))
st = time.time()
output = calculate.calculate_z(max_iter, zs, cs)
et = time.time()
print(f"Took {et-st} seconds")
if __name__ == '__main__':
calc_julia(desired_width=1000, max_iter=300)
И да Я знаю, что здесь есть ряд вещей, которые можно улучшить , например, cs может быть просто скаляром, поскольку все они одинаковы. Это скорее упражнение, но оно привело к неожиданным результатам для оптимизации.