2009-09-25 9 views
6
import threading 

mydata = threading.local() 

def run(): 
    # When will the garbage collector be able to destroy the object created 
    # here? After the thread exits from ``run()``? After ``join()`` is called? 
    # Or will it survive the thread in which it was created, and live until 
    # ``mydata`` is garbage-collected? 
    mydata.foo = object() 

t = threading.Thread(target=run) 
t.start() 
t.join() 

Antwort

3

Mark hatte es fast richtig - im Wesentlichen "mydata" werden Verweise auf alle TL Variablen in sie halten, was sie geschaffen wurden Faden von. Nämlich ...:

import threading 
import gc 

mydata = threading.local() 

class x: 
    def __del__(self): 
     print "x got deleted!" 

def run(): 
    mydata.foo = x() 

t = threading.Thread(target=run) 
print "t created" 
gc.collect() 
t.start() 
print "t started" 
gc.collect() 
del mydata 
print "mydata deleted" 
gc.collect() 
t.join() 
print "t joined" 
gc.collect() 
print "Done!" 

Emits:

t created 
t started 
x got deleted! 
mydata deleted 
t joined 
Done! 

gc spielt eigentlich keine Rolle in CPython, so dass Sie den Code vereinfachen kann bis auf:

import threading 

mydata = threading.local() 

class x: 
    def __init__(self): 
     print "x got created!" 
    def __del__(self): 
     print "x got deleted!" 

def run(): 
    mydata.foo = x() 

t = threading.Thread(target=run) 
print "t created" 
t.start() 
print "t started" 
del mydata 
print "mydata deleted" 
t.join() 
print "t joined" 
print "Done!" 

und noch sehen ...:

t created 
x got created! 
t started 
x got deleted! 
mydata deleted 
t joined 
Done! 
0

ein paar einfache Änderungen an Ihrem Programm Indem und zwingt eine Garbage Collection nach jedem Schritt des Gewindes, so scheint es, dass foo nicht, bis das Programm beendet ist gesammelt werden - mit anderen Worten, nach der Faden geht von Umfang.

import threading 
import gc 

mydata = threading.local() 

class x: 
    def __del__(self): 
     print "x got deleted!" 

def run(): 
    mydata.foo = x() 

t = threading.Thread(target=run) 
print "t created" 
gc.collect() 
t.start() 
print "t started" 
gc.collect() 
t.join() 
print "t joined" 
gc.collect() 
print "Done!" 

Ausgang (mit Python 2.6, Windows):

 
>C:\temp\py\t.py 
t created 
t started 
t joined 
Done! 
x got deleted! 
+0

Gute Analyse, aber das fehlende Bit ist, dass _mydata_ weggehen ist, was Sie brauchen - ich muss eine neue Antwort öffnen, um formatierten Code anzuzeigen, aber das Wesentliche ist das gleiche wie Ihres. –

1

Vielen Dank! Es scheint, dass Mark das Programm verhält sich anders unter CPython 2.5 und 2.6:

import threading 
import gc 
import platform 

print "Python %s (%s)" % (platform.python_version(), " ".join(platform.python_build())) 

mydata = threading.local() 

class x: 
    def __del__(self): 
     print "x got deleted!" 

def run(): 
    mydata.foo = x() 

t = threading.Thread(target=run) 
print "t created" 
gc.collect() 
t.start() 
print "t started" 
gc.collect() 
del mydata 
print "mydata deleted" 
gc.collect() 
t.join() 
print "t joined" 
gc.collect() 
print "Done!" 

Emits (unter Ubuntu 8.04 i386):

Python 2.5.2 (r252:60911 Jul 31 2008 19:40:22) 
t created 
t started 
mydata deleted 
x got deleted! 
Exception in thread Thread-1: 
Traceback (most recent call last): 
    File "/usr/lib/python2.5/threading.py", line 486, in __bootstrap_inner 
    self.run() 
    File "/usr/lib/python2.5/threading.py", line 446, in run 
    self.__target(*self.__args, **self.__kwargs) 
    File "./x.py", line 14, in run 
    mydata.foo = x() 
NameError: global name 'mydata' is not defined 

t joined 
Done! 

Und:

Python 2.6.2 (r262:71600 Sep 19 2009 17:24:20) 
t created 
t started 
x got deleted! 
mydata deleted 
t joined 
Done! 
3

Hier ist meine Antwort, da Ich kann die Schlussfolgerung in den vorherigen Antworten nicht sehen.

Ich fing an, das gleiche zu fragen und versuchte ein Testprogramm, das dem in anderen Antworten ähnlich ist, und meine Schlussfolgerung war, dass sie GCed früher als das Ende des Programms erhalten, was bedeutet, dass diese Referenzen als bestimmt werden können Müll, sobald der Faden selbst stirbt.

import time 
import threading 
import gc 

data = threading.local() 

class Resource(object): 
    def __init__(self): 
     self.name = threading.currentThread().name 
     print 'create: %s' % self.name 

    def __del__(self): 
     print 'delete: %s' % self.name 

def access_thlocal(): 
    data.key = Resource() 

for i in range(0, 10): 
    threading.Thread(target=access_thlocal).start() 
time.sleep(1) 
print "Triggering GC" 
gc.collect() 
time.sleep(1) 

Der Ausgang:

create: Thread-1 
create: Thread-2 
delete: Thread-1 
create: Thread-3 
delete: Thread-2 
create: Thread-4 
delete: Thread-3 
create: Thread-5 
delete: Thread-4 
create: Thread-6 
delete: Thread-5 
create: Thread-7 
delete: Thread-6 
create: Thread-8 
delete: Thread-7 
create: Thread-9 
delete: Thread-8 
create: Thread-10 
delete: Thread-9 
Triggering GC 
delete: Thread-10 

Wie Sie sehen können, die löschen ist scheinen, sobald der Thread stirbt passieren.

Verwandte Themen