2010-12-29 6 views
3

Schließlich schrieb ich einen einfachen Generator von Permutationen in Python (Implementierung von "plain changes" -Algorithmus von Knuth in "The Art ... 4" beschrieben). Ich war neugierig auf die Unterschiede in der Ausführungszeit zwischen Python2 und Python3. Hier ist meine Funktion:Leicht unterschiedliche Ausführungszeiten zwischen Python2 und Python3

def perms(s): 
    s = tuple(s) 
    N = len(s) 
    if N <= 1: 
     yield s[:] 
     raise StopIteration() 
    for x in perms(s[1:]): 
     for i in range(0,N): 
     yield x[:i] + (s[0],) + x[i:] 

In der python3 Version, die ich gerade geändertener Druck x (x) als Druck Druck ist eine Funktion in py3. Ich testete beide mit Timeit-Modul.

Meine Tests:

$ echo "python2.6:" && ./testing.py && echo "python3:" && ./testing3.py 

python2.6:

args time[ms] 
1 0.003811 
2 0.008268 
3 0.015907 
4 0.042646 
5 0.166755 
6 0.908796 
7 6.117996 
8 48.346996 
9 433.928967 
10 4379.904032 

python3:

args time[ms] 
1 0.00246778964996 
2 0.00656183719635 
3 0.01419159912 
4 0.0406293644678 
5 0.165960511097 
6 0.923101452814 
7 6.24257639835 
8 53.0099868774 
9 454.540967941 
10 4585.83498001 

Wie Sie, für die Anzahl der Argumente weniger als 6 sehen kann, Python 3 schneller, aber dann Rollen sind umgekehrt und python2.6 ist besser. Da ich ein Anfänger in Python-Programmierung bin, frage ich mich, warum ist das so? Oder vielleicht ist mein Skript für python2 optimiert?

Vielen Dank im Voraus für die Art Antwort :)

+0

Bitte verwenden Sie die richtige Formatierung. –

+0

Formatieren Sie zuerst Ihren Code mit der Schaltfläche '{}'. Dann erkläre, warum das wichtig ist. –

+0

Dies ist nicht wahrscheinlich, dass es wirklich wichtig ist, nur Neugier. – ecik

Antwort

2

Das ist eigentlich eine sehr interessante Frage.

Ich habe das folgende Skript verwendet, das auf Python 2.6, 2.7, 3.0, 3.1 und 3.2 ausgeführt wird.

Die Plattform ist Ubuntu 10.10, 64 Bit, und alle Versionen von Python wurden aus der Quelle kompiliert.Ich erhalte die folgenden Ergebnisse:

[email protected]:~$ py27 perms.py 
args time[ms] 
1 0.002221 
2 0.005072 
3 0.010352 
4 0.027648 
5 0.111339 
6 0.618658 
7 4.207046 
8 33.213019 
9 294.044971 
10 2976.780891 

[email protected]:~$ py32 perms.py 
args time[ms] 
1 0.001725 
2 0.004997 
3 0.011208 
4 0.032815 
5 0.139474 
6 0.761153 
7 5.068729 
8 39.760470 
9 356.358051 
10 3566.874027 

Nach weiterem Experimentieren, ich den Unterschied in der Leistung an das Fragment verfolgt: x[:i] + (s[0],) + x[i:] Wenn ich nur ein Tupel am Anfang der Schleife berechnen und senden Sie es für jede yield-Anweisung, beide Versionen von Python laufen mit der gleichen Geschwindigkeit. (Und die Permutationen sind falsch, aber das ist nicht der Punkt.)

Wenn ich dieses Fragment von selbst Zeit, ist es deutlich langsamer.

Ich benutzte als nächstes dis.dis(), um den Bytecode zu betrachten, der von beiden Versionen erzeugt wurde.

[email protected]:~/src/Python-3.0.1$ py32 
Python 3.2b2 (r32b2:87398, Dec 21 2010, 21:39:59) 
[GCC 4.4.5] on linux2 
Type "help", "copyright", "credits" or "license" for more information. 
>>> import dis 
>>> s=(1,2,3,4,5) 
>>> x=(1,2,3,4,5,6,7,8) 
>>> def f(s,x): 
... return x[:3] + (s[0],) + x[3:] 
... 
>>> dis.dis(f) 
    2   0 LOAD_FAST    1 (x) 
       3 LOAD_CONST    0 (None) 
       6 LOAD_CONST    1 (3) 
       9 BUILD_SLICE    2 
      12 BINARY_SUBSCR   
      13 LOAD_FAST    0 (s) 
      16 LOAD_CONST    2 (0) 
      19 BINARY_SUBSCR   
      20 BUILD_TUPLE    1 
      23 BINARY_ADD   
      24 LOAD_FAST    1 (x) 
      27 LOAD_CONST    1 (3) 
      30 LOAD_CONST    0 (None) 
      33 BUILD_SLICE    2 
      36 BINARY_SUBSCR   
      37 BINARY_ADD   
      38 RETURN_VALUE   
>>> exit() 
[email protected]:~/src/Python-3.0.1$ py26 
Python 2.6.6 (r266:84292, Oct 24 2010, 15:27:46) 
[GCC 4.4.5] on linux2 
Type "help", "copyright", "credits" or "license" for more information. 
>>> import dis 
>>> s=(1,2,3,4,5) 
>>> x=(1,2,3,4,5,6,7,8) 
>>> def f(s,x): 
... return x[:3] + (s[0],) + x[3:] 
... 
>>> dis.dis(f) 
    2   0 LOAD_FAST    1 (x) 
       3 LOAD_CONST    1 (3) 
       6 SLICE+2    
       7 LOAD_FAST    0 (s) 
      10 LOAD_CONST    2 (0) 
      13 BINARY_SUBSCR  
      14 BUILD_TUPLE    1 
      17 BINARY_ADD   
      18 LOAD_FAST    1 (x) 
      21 LOAD_CONST    1 (3) 
      24 SLICE+1    
      25 BINARY_ADD   
      26 RETURN_VALUE   
>>> 

Der generierte Bytecode unterscheidet sich zwischen den beiden Versionen sehr. Leider weiß ich nicht, warum der Bytecode anders ist, also habe ich die Frage wirklich nicht beantwortet. Aber es gibt tatsächlich einen signifikanten Leistungsunterschied beim Schneiden und beim Aufbau von Tupeln.

+0

Warum sagen Sie, dass diese Permutationen falsch sind? Ich sehe nicht, was in ihnen falsch sein könnte. –

+0

@kosa: Um die Laufzeit für die Erstellung des Tupels zu entfernen, habe ich ein Tupel der richtigen Länge erstellt und das gleiche Tupel für alle Iterationen des Bereichs (0, N) zurückgegeben. Die tatsächlichen Permutationen, die für diesen speziellen Test zurückgegeben wurden, waren nicht korrekt, aber die Laufzeit war für Python 2 und 3 identisch. Nahe zwei Drittel der Laufzeit von perms() ist das Fragment: x [: i] + (s [ 0],) + x [i:]. Da dieses Fragment in Python 3 25% langsamer ist und 65% der Laufzeit ausmacht, sollte die Gesamtlaufzeit etwa 17% langsamer sein, was ungefähr den Tests entspricht. – casevh

+0

Ah, jetzt sehe ich. Nun, das ist die Antwort, auf die ich gehofft habe. Vielen Dank! –

0

ich statistisch nicht signifikant, diese Zahlen sicherlich nennen würde.

Es gibt zu viele Faktoren bei diesen Variationen, die wirklich eine Bedeutung haben.

4

Quoting:

Das Nettoergebnis des 3,0 Verallgemeinerungen ist, dass Python 3.0 läuft die pystone Benchmark etwa 10% langsamer als Python 2.5. Am wahrscheinlichsten ist die größte Ursache ist die Entfernung von spezielle Gehäuse für kleine ganze Zahlen. Es gibt Raum für Verbesserungen, aber es wird passieren, nachdem 3.0 veröffentlicht wird!

>>> 4585.83498001/4379.904032 
1.0470172283468882 

Sie sind also etwa 5% Verlangsamung zu sehen. Der zitierte Text sagt eine 10% ige Verlangsamung voraus. Also würde ich das als eine vernünftige Verlangsamung akzeptieren.

Jedoch wurde verbessert, wie man sehen kann here und here. Also versuchen Sie es mit 3.1 oder 3.2, wenn Sie über die Verlangsamung von 5% besorgt sind.

+0

@ ΤΖΩΤΖΙΟΥ Das habe ich nicht gesagt. Es ist ein Zitat aus den 3.0 Release Notes. Und die Verbesserungen sind nach der Version 3.0 passiert: in 3.1 und 3.2 wie in meinem letzten Absatz erwähnt. – marcog

+0

Sie haben Recht; Ich sah deine Antwort auf einem Laptop mit einem sehr kontrastarmen LCD-Bildschirm (lies: alt), so dass der Zitathintergrund nicht so sichtbar war wie er sein sollte. – tzot

Verwandte Themen