2014-04-14 5 views
8

Ich habe diese einfache Code, der mich zu messen dazu beigetragen, wie Klassen mit __slots__ durchführen (aus here genommen):Mit __slots__ unter PyPy

import timeit 

def test_slots(): 
    class Obj(object): 
     __slots__ = ('i', 'l') 

     def __init__(self, i): 
      self.i = i 
      self.l = [] 

    for i in xrange(1000): 
     Obj(i) 

print timeit.Timer('test_slots()', 'from __main__ import test_slots').timeit(10000) 

Wenn ich es über python2.7 laufen - ich würde 6 etwas umgehen Sekunden - ok, es ist wirklich schneller (und auch speichereffizienter) als ohne Slots.

Aber wenn ich den Code unter PyPy (unter Verwendung von 2.2.1 - 64bit für Mac OS/X), beginnt es zu 100% CPU verwenden und "nie" zurück (Minuten gewartet - kein Ergebnis).

Was ist los? Sollte ich __slots__ unter PyPy verwenden?

Hier ist, was passiert, wenn ich andere Nummer timeit() passieren:

timeit(10) - 0.067s 
timeit(100) - 0.5s 
timeit(1000) - 19.5s 
timeit(10000) - ? (probably more than a Game of Thrones episode) 

Vielen Dank im Voraus.


Beachten Sie, dass das gleiche Verhalten beobachtet wird, wenn ich namedtuple s verwenden:

import collections 
import timeit 

def test_namedtuples(): 
    Obj = collections.namedtuple('Obj', 'i l') 

    for i in xrange(1000): 
     Obj(i, []) 

print timeit.Timer('test_namedtuples()', 'from __main__ import test_namedtuples').timeit(10000) 
+3

Unabhängig von allem anderen, ein Programm, das entweder endlos oder 60x unter CPython läuft, ist ein Bug und sollte mit den PyPy-Jungs ausgelöst werden. – delnan

+0

Ich würde tatsächlich erwarten, dass die '__slots__'-Version langsamer ist, da diese Klassen für den Speicherplatz optimiert sind und nicht für das Abrufen von Attributen optimiert sind. – wheaties

+0

@wheaties yup, aber der Benchmark zeigt, dass 'slots' und' namedtuples' auch schneller sind: http://stackoverflow.com/questions/1336791/dictionary-vs-object-which-is-more-efficient-and-why/1336890 # 1336890 – alecxe

Antwort

11

In jedem der 10.000 oder so Iterationen des timeit Code, wird die Klasse von Grund auf neu erstellt. Das Erstellen von Klassen ist wahrscheinlich keine gut optimierte Operation in PyPy. Schlimmer noch, wenn Sie dies tun, werden Sie wahrscheinlich alle Optimierungen verwerfen, die das JIT von der vorherigen Inkarnation der Klasse erfahren hat. PyPy neigt dazu, langsam zu sein, bis sich das JIT erwärmt hat. Wenn Sie also Dinge tun, bei denen es sich wiederholt aufwärmen muss, wird Ihre Leistung beeinträchtigt.

Die Lösung hier ist natürlich, einfach die Klassendefinition außerhalb des Benchmarks zu verschieben.

+0

Das ist interessant und ein wenig enttäuschend. Die Klassenerstellung ist eine leichte Operation unter CPython, und es gibt Programmierstile, die davon abhängen. – Marcin

+0

@Marcin Ich glaube, dass das PyPy-Team Code-Snippets betrachtet, die langsamer sind als CPython, um Fehler zu sein. Vor allem, wenn Sie die schnelle Erstellung von kurzlebigen Klassen in echtem Code kennen. – kwatford

+2

Es ist erwähnenswert, dass selbst unter CPython das Erstellen einer neuen Klasse nicht so günstig ist. Klassen belegen mehrere hundert Bytes, viel mehr als ein typisches Objekt, und befinden sich in mehreren Caches, so dass die Zuweisung und Freigabe viel langsamer ist als bei einem durchschnittlichen Objekt. –

8

Um die Frage direkt im Titel zu beantworten: __slots__ ist sinnlos für (aber tut nicht weh) Leistung in PyPy.

+0

Danke, Armin. Könnten Sie bitte Informationen darüber hinzufügen oder auf sie verweisen, wie PyPy Instanzvariablen speichert? – alecxe

+4

@alecxe http://morepypy.blogspot.ca/2010/11/efficiently-implementing-python-objects.html skizziert den Ansatz. –