stavo scrivendo un nuovo generatore di numeri casuali per NumPy che produce numeri casuali in base ad una distribuzione arbitraria, quando mi sono imbattuto in questo comportamento davvero strano:creando piccoli array in Cython prende una quantità colossale di tempo
questo è prova. pisside
setup.py
from distutils.core import setup
from Cython.Build import cythonize
setup(name = "simple cython func",ext_modules = cythonize('test.pyx'),)
il profiling del codice
#!/usr/bin/python
from __future__ import division
import subprocess
import timeit
#Compile the cython modules before importing them
subprocess.call(['python', 'setup.py', 'build_ext', '--inplace'])
sstr="""
import test
import numpy
u=numpy.random.random(10)
a=numpy.random.random(10)
a=numpy.cumsum(a)
a/=a[-1]
r=numpy.empty(10,int)
"""
print "binary search: creates an array[N] and performs N binary searches to fill it:\n",timeit.timeit('numpy.searchsorted(a,u)',sstr)
print "Simple replacement for binary search:takes the same args as np.searchsorted and similarly returns a new array. this performs only one trivial operation per element:\n",timeit.timeit('test.BSReplacement(a,u)',sstr)
print "barebones function doing nothing:",timeit.timeit('test.BareBones(a,u,r)',sstr)
print "Untyped inputs and doing N iterations:",timeit.timeit('test.UntypedWithLoop(a,u,r)',sstr)
print "time for just np.empty()",timeit.timeit('numpy.empty(10,int)',sstr)
L'implementazione della ricerca binaria è nell'ordine di len(u)*Log(len(a))
tempo di esecuzione. La banale funzione cython richiede l'esecuzione di len(u)
. Entrambi restituiscono un array int 1D di len (u).
tuttavia, anche questa non banale implementazione computazionale richiede più tempo della ricerca binaria completa nella libreria numpy. (È stato scritto in C: https://github.com/numpy/numpy/blob/202e78d607515e0390cffb1898e11807f117b36a/numpy/core/src/multiarray/item_selection.c vedi PyArray_SearchSorted)
I risultati sono:
binary search: creates an array[N] and performs N binary searches to fill it:
1.15157485008
Simple replacement for binary search:takes the same args as np.searchsorted and similarly returns a new array. this performs only one trivial operation per element:
3.69442796707
barebones function doing nothing: 0.87496304512
Untyped inputs and doing N iterations: 0.244267940521
time for just np.empty() 1.0983929634
Perché la np.empty() passo prendendo così tanto tempo? e cosa posso fare per ottenere un array vuoto che posso restituire?
La funzione C esegue questo AND esegue un intero gruppo di controlli di integrità e utilizza un algoritmo più lungo nel ciclo interno. (Ho rimosso tutta la logica tranne la stessa ciclo fro mio esempio)
Aggiorna
Sembra che vi sono due problemi distinti:
- Il np.empty (10) la chiamata da sola ha un sovraccarico enorme e richiede tutto il tempo necessario per searchsorted per creare un nuovo array ed eseguire 10 ricerche binarie su di esso
- Solo dichiarando la sintassi del bufferIlha anche un sovraccarico che richiede più tempo rispetto alla ricezione delle variabili non tipizzate E iterando 50 volte.
risultati per 50 iterazioni:
binary search: 2.45336699486
Simple replacement:3.71126317978
barebones function doing nothing: 0.924916028976
Untyped inputs and doing N iterations: 0.316384077072
time for just np.empty() 1.04949498177
È confuso quando si nominano il 'import'ed e' cimport'ed 'numpy's lo stesso, nell'immagine di scikits che fanno normalmente' import numpy come np; cimport numpy as cnp' per differenziarli. Ma penso che il 'np' nella tua chiamata a' np.empty' sia quello 'importato', e non ci sia 'cimport'ed, quindi è una chiamata alla funzione Python, con il suo overhead ben noto. Probabilmente puoi chiamare ['PyArray_SimpleNew'] (http://docs.scipy.org/doc/numpy/reference/c-api.array.html#PyArray_SimpleNew) da Cython per evitarlo, non so come. Se ti preoccupi di questo livello di ottimizzazione, rilascia Cython e vai C-API fino in fondo ... – Jaime
@Jaime importando e poi cimportando numpy dato che np è un uso standard, anche se confuso. L'ho visto fare come hai detto anche se http://docs.cython.org/src/tutorial/numpy.html#adding-types penso che il modo in cui i documenti di cython suggeriscono probabilmente riassocia le varianti di cython allo stesso nome quando disponibile proprio come succede quando si ha una collisione di spazio nome standard in python – JoshAdel
@JoshAdel Il mio punto è che non mi è chiaro se chiamare 'np.empty' sta facendo una chiamata a una funzione Python, che penso spiegherebbe la overhead, o una variante di Cython, che indicherebbe qualcosa in Cython non è così buona. Ma l'unico Cython che abbia mai scritto è stato "Hello World!" dai documenti: l'ho trovato confuso, principalmente dal fatto che era difficile capire se qualcosa fosse in esecuzione in C veloce o in Python lento e spostato fino all'API Python/NumPy. Quindi la mia opinione è parziale e non molto informata ... – Jaime