2015-11-06 32 views
5

Ho notato per caso che un semplice programma che genera una classe da un file di dati di grandi dimensioni è molto più veloce in Python 2.7 contro 3.5. Ho letto here che l'uso di numeri interi "infinita precisione" era da biasimare per rallentamento della semplice enumerazione, ma anche quando ho provato un semplice test istanziare questa classe ho scoperto che Python 3 è stata significativamente più lenta:Istanza di classe più lenta in Python 3 che Python 2

class Benchmark(object): 
    def __init__(self): 
     self.members = ['a', 'b', 'c', 'd'] 


def test(): 
    test = Benchmark() 

if __name__ == '__main__': 
    import timeit 
    print(timeit.timeit("test()", setup="from __main__ import test")) 

ho pensato forse era a che fare con le dimensioni di ogni istanza classe, ma l'istanza Python 3 era più piccola di 2 (56 vs 64)

$python3 benchmarks.py 
0.7017288669958361 
$python benchmarks.py 
0.508942842484 

ho provato molte variazioni su questo tema, anche con 3.4 da un macchina diversa, e ottengono sempre gli stessi risultati. Qualche idea su cosa sta succedendo?

+0

Il duplicato collegato riguarda Python 3 che è più veloce di Python 2, mentre questa domanda riguarda il contrario. Votazione per riaprire. – jwodder

+1

Cosa ottieni se semplicemente esegui 'timeit (" Benchmark() ", ...)'? Sembra che tu non voglia realmente temporizzare la chiamata di funzione, l'assegnazione di variabile, ecc. E cosa succede se hai solo la volta della creazione della lista? – shx2

+0

Ottengo gli stessi risultati fino a quando non li abbasso alla sola classe. Ho fatto solo 'class A: pass' e ho cambiato la chiamata' timeit' a 'timeit (" A() ", setup =" da __main__ import A ")' e Py2 era due volte più lento di Py3. Qualunque siano i risultati iniziali, dubito che questo abbia a che fare con l'istanziazione degli oggetti. Se faccio quella 'classe A (oggetto): pass', i risultati sono indistinguibili. –

risposta

3

Non sta misurando classe tempo di istanza, si sta misurando classe di un'istanza, più l'assegnazione, oltre la creazione di elenchi, ...

Ecco un punto di riferimento corretto:

$ python -m timeit -s 'class C(object): pass' 'C()' 
10000000 loops, best of 3: 0.0639 usec per loop 
$ python3 -m timeit -s 'class C(object): pass' 'C()' 
10000000 loops, best of 3: 0.0622 usec per loop 

Come si può vedere, Python 3 è visivamente più veloce.

+0

Inoltre, Python 3 sta risparmiando più memoria di quanto si pensi; l'overhead di dimensione totale di un'istanza è il 'sys.getsizeof' per l'istanza più il' sys.getsizeof' per il suo '__dict__' (a meno che' __dict__' non sia stato soppresso al livello C o usando '__slots__'). [Python 3.3 ha introdotto i dizionari di chiavi condivise] (https://docs.python.org/3/whatsnew/3.3.html#pep-412), quindi oltre alla struttura dell'oggetto che si restringe leggermente (8 byte su x64), il la dimensione di '__dict__' per le singole istanze di attributo diminuisce di un fattore di ~ 3x (sulla mia macchina Linux x64, da 280 byte a 96 byte). Grandi risparmi per molte istanze. – ShadowRanger

+0

Andrea: si potrebbe desiderare che il test assegni un singolo membro letterale di compilazione; mentre la costruzione delle liste, le chiamate di funzione e l'assegnazione degli oggetti non fanno correttamente parte di un buon test, l'assegnazione di almeno un attributo di istanza in '__init__' dovrebbe far parte di un test ragionevole. – ShadowRanger

+0

@ShadowRanger: se mischi troppe cose nei benchmark, non scoprirai mai cosa c'è che non va. Questa domanda è un esempio chiaro: l'OP ritiene che l'istanziazione di classe sia più lenta mentre non lo è. –