Я проверил вас проблемы со следующим кодом:
#cython: wraparound=False
#cython: boundscheck=False
#cython: cdivision=True
#cython: nonecheck=False
#cython: profile=False
def loop(int k):
return real_loop(k)
def loop2(int k):
cdef float a
real_loop2(k, &a)
return a
def loop3(int k):
real_loop3(k)
return None
def loop4(int k):
return real_loop4(k)
def loop5(int k):
cdef float a
real_loop5(k, &a)
return a
cdef float real_loop(int k):
cdef int i
cdef float a
a = 0.
for i in range(k):
a += a**2/(a + 1)
return a
cdef void real_loop2(int k, float *a):
cdef int i
a[0] = 0.
for i in range(k):
a[0] += a[0]**2/(a[0] + 1)
cdef void real_loop3(int k):
cdef int i
cdef float a
a = 0.
for i in range(k):
a += a**2/(a + 1)
cdef float real_loop4(int k):
cdef int i
cdef float a
a = 0.
for i in range(k):
a += a*a/(a + 1)
return a
cdef void real_loop5(int k, float *a):
cdef int i
a[0] = 0.
for i in range(k):
a[0] += a[0]*a[0]/(a[0] + 1)
где real_loop()
близка к вашей функции, с измененной формулой a
, так как оригинал один казалось странным.
Функция real_loop2()
не возвращает никакого значения, просто обновляя a
по ссылке.
Функция real_loop3()
не возвращает никакой ценности.
Проверка сгенерированного C
код real_loop3()
можно видеть, что цикл есть, и код называется ... но у меня был тот же вывод, как @dmytro, изменение k
не изменит сроки значительно ... поэтому должен быть пункт, который мне здесь не хватает.
С таймингами ниже мы можем сказать, что return
не является узким местом, так как real_loop2()
и real_loop5()
имеют не возвращает никакого значения, и их производительность такая же, как и real_loop()
real_loop4()
соответственно.
In [2]: timeit _stack.loop(100000)
1000 loops, best of 3: 1.71 ms per loop
In [3]: timeit _stack.loop2(100000)
1000 loops, best of 3: 1.69 ms per loop
In [4]: timeit _stack.loop3(100000)
10000000 loops, best of 3: 78.5 ns per loop
In [5]: timeit _stack.loop4(100000)
1000 loops, best of 3: 913 µs per loop
In [6]: timeit _stack.loop5(100000)
1000 loops, best of 3: 979 µs per loop
Обратите внимание на ~ 2X ускорение меняется a**2
по a*a
, так как a**2
требует вызова функции powf()
внутри цикла.
Трудно сказать - интересно, будет ли компилятор достаточно умен, чтобы увидеть, что 'real_loop' не обновляет какие-либо глобальные переменные, и он не меняет никаких аргументов, поэтому его можно превратить в no -op. – mgilson
Вы пытались «разбить» два сгенерированных файла C, чтобы увидеть различия? Во всяком случае, возможно, это потому, что cython видит, что функции без 'return' бесполезны и вообще не работают. – Bakuriu
@ Бакуриу да, это то, что я думаю. вероятно, вообще не делают петлю. Я не знаю, как вчера, когда я пытаюсь по-разному закодировать его, я получаю иногда смешную работу, например, в 12 000 раз быстрее. –