2016-05-05 12 views
11

Questo question e il mio answer mi hanno fatto riflettere su questa particolare differenza tra Python 2.7 e Python 3.4. Prendete il codice di esempio semplice:L'affettatura è molto più lenta in Python 3.4?

import timeit 
import dis 

c = 1000000 
r = range(c) 
def slow(): 
    for pos in range(c): 
     r[pos:pos+3] 

dis.dis(slow) 

time = timeit.Timer(lambda: slow()).timeit(number=1) 
print('%3.3f' % time) 

In Python 2.7, ho sempre arrivare 0.165~ e per Python 3.4 ho sempre capito 0.554~. L'unica differenza significativa tra i disassemblaggi è che Python 2.7 emette il codice byte SLICE+3 mentre Python 3.4 emette BUILD_SLICE seguito da BINARY_SUBSCR. Nota che ho eliminato i candidati per un potenziale rallentamento dall'altra domanda, vale a dire le stringhe e il fatto che xrange non esiste in Python 3.4 (che dovrebbe essere comunque simile alla classe range di quest'ultimo).

Utilizzare itertools'islice produce tempi quasi identici tra i due, quindi ho il forte sospetto che sia l'affettatura che è la causa della differenza qui.

Perché sta succedendo questo e c'è un collegamento a una fonte autorevole che documenta un cambiamento nel comportamento?

MODIFICA: in risposta alla risposta, ho spostato gli oggetti range in list, che ha dato un notevole aumento di velocità. Tuttavia, poiché ho aumentato il numero di iterazioni in timeit, ho notato che le differenze di temporizzazione sono diventate sempre più grandi. Come controllo di integrità, ho sostituito l'affettamento con None per vedere cosa sarebbe successo.

500 iterazioni in timeit.

c = 1000000 
r = list(range(c)) 
def slow(): 
    for pos in r: 
     None 

cede rispettivamente 10.688 e 9.915. La sostituzione del ciclo for con for pos in islice(r, 0, c, 3) produce rispettivamente 7.626 e 6.270. La sostituzione di None con r[pos] ha prodotto rispettivamente 20~ e 28~. r[pos:pos+3] produce rispettivamente 67.531 e 106.784.

Come potete vedere, le differenze di temporizzazione sono enormi. Ancora una volta, sono ancora convinto che il problema non sia direttamente correlato a range.

+0

Stavi usando 'range' o' xrange' in Python 2? – cdarke

+0

Riprovare con 'r = list (range (c))'. –

+0

Gli oggetti Python 3 'range' e Python 2' xrange' non sono simili in questo contesto. Gli oggetti Python 3 'range' supportano l'slicing, gli oggetti Python 2' xrange' non supportano l'slicing. – cdarke

risposta

10

Su Python 2.7, si sta iterando su un elenco e si affetta un elenco. Su Python 3.4, si sta iterando su uno range e su affettando uno range.

Quando eseguo un test con una lista su entrambe le versioni di Python:

from __future__ import print_function 
import timeit 
print(timeit.timeit('x[5:8]', setup='x = list(range(10))')) 

ricevo 0.243554830551 seconds on Python 2.7 e 0.29082867689430714 seconds on Python 3.4, una differenza molto più piccolo.


La differenza di prestazioni che si vede dopo aver eliminato l'oggetto range è molto più piccolo. Deriva principalmente da due fattori: l'aggiunta è un po 'più lenta su Python 3, e Python 3 deve passare attraverso __getitem__ con un oggetto fetta da affettare, mentre Python 2 ha __getslice__.

Non è stato possibile replicare la differenza di orario che si è visto con r[pos]; potresti aver avuto qualche fattore di confondimento in quel test.

+1

L'aumento del numero di iterazioni inizia a mostrare intervalli sempre più grandi nelle differenze di temporizzazione. '1.352' e' 2.171' rispettivamente per 10 iterazioni. Non sono sicuro di cosa mi manchi qui. –

+0

@ user6292850: Come stai eseguendo quel test? – user2357112

+1

Sto semplicemente aumentando il parametro number in 'timeit', e eseguendo' python test.py' seguito da 'python3 test.py'. –

Problemi correlati