Wenn ein Generator nicht mehr verwendet wird, sollte es Müll gesammelt werden, oder? Ich habe den folgenden Code ausprobiert, aber ich bin mir nicht sicher, an welcher Stelle ich falsch lag.Wird ein Python-Generator Müll gesammelt, wenn er nicht mehr verwendet wird, aber noch nicht StopIteration erreicht?
import weakref
import gc
def countdown(n):
while n:
yield n
n-=1
cd = countdown(10)
cdw = weakref.ref(cd)()
print cd.next()
gc.collect()
print cd.next()
gc.collect()
print cdw.next()
Auf der vorletzten Zeile, rief ich Garbage Collector und da es keinen Aufruf cd
mehr. gc
sollte frei cd
richtig sein. Aber wenn ich cdw.next()
anrufe, druckt es noch 8. Ich versuchte ein paar mehr cdw.next()
, es konnte den ganzen Rest bis StopIteration erfolgreich drucken.
Ich versuchte dies, weil ich verstehen wollte, wie Generator und Coroutine arbeiten. Auf Folie 28 von David Beazleys PyCon-Präsentation "Ein kurioser Kurs über Coroutines und Parallelität" sagte er, dass eine Coroutine auf unbestimmte Zeit laufen könnte, und wir sollten .close()
verwenden, um sie herunterzufahren. Dann sagte er, dass Garbage Collector .close()
anrufen wird. In meinem Verständnis, sobald wir .close()
selbst aufgerufen haben, wird gc
wieder .close()
aufrufen. Wird gc
eine Warnung erhalten, dass es .close()
auf einer bereits geschlossenen Coroutine nicht aufrufen kann?
Danke für alle Eingaben.
Eigentlich könnte PyPy das tun, wenn 'func' in einer Schleife aufgerufen wird. Es kann nicht einmal den Generator überhaupt zuordnen. (Ich bezweifle es derzeit, wenn Generatoren derzeit so unoptimiert sind, wie Fijal sagt, aber dies tut dies bereits mit vielen anderen Objekten.) Das Problem ist nicht, dass Python dynamisch ist, das Problem ist, dass CPython nicht einmal versucht, zu regieren aus Dynamik, auch wenn es möglich wäre. Natürlich ist die Refcount-Erklärung am Ende auch CPython-spezifisch. Das 'c()' in Ihrem Beispiel kann sehr gut etwas in PyPy, Jython oder IronPython drucken. – delnan
@delnan - Sie haben das Referenzzählungsbit korrekt. Wie behandelt PyPy den Fall, in dem Sie etwas wie 'localhosts() [other_str [:: 2] [:: - 1]]' machen, wenn es nicht vor der Zeit weiß, was 'other_str' (und folglich ist es Scheiben) werden sein? Zugegeben, das ist ein wahnsinniger Fall, aber der Python-Interpreter sollte es erlauben. Ich denke, es könnte nach "Einheimische", "Vars" und "Globals" aussehen und die sofortige Garbage-Collection nur dann deaktivieren, wenn sie nicht vorhanden sind oder etwas ... aber ich denke, dass die dynamische Natur die sofortige Sammlung verhindert *manche Fälle ... – mgilson
Es handhabt so, wie es alle anderen dynamischen Seltsamkeiten behandelt (seltsame Typen tauchen auf, ersetzt Methoden oder Klassen oder Module, fummelt mit '__dict__', etc): Es kommt aus dem optimierten Code heraus und macht das ineffiziente Ding (manchmal sogar noch mehr als das, was CPython macht, beginnend mit dem, was es bereits getan hätte (z. B. das Zuweisen von Zwischenobjekten), wenn es überhaupt nicht optimiert worden wäre. Dies verfolgt den JIT-Compiler 101. Wie hat es PyPy gelungen, * irgendetwas * zu optimieren? – delnan