2009-09-25 5 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() 

risposta

3

Mark aveva quasi subito - essenzialmente "mydata" terrà i riferimenti a tutte le variabili TL in esso, qualunque discussione sono stati creati a partire dal. Vale a dire ...:

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!" 

Emette:

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

gc in realtà non ha alcun ruolo qui a CPython, in modo da poter semplificare il codice fino a:

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!" 

e ancora vedere ...:

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

Facendo un paio di semplici modifiche al vostro programma e costringendo una garbage collection dopo ogni passo della filettatura, sembra che foo non possono essere raccolti fino a quando il programma è finito - in altre parole, dopo il filo si spegne di scopo.

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!" 

uscita (utilizzando Python 2.6, Windows):

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

Buona analisi, ma il bit mancante è che _mydata_ sta andando via è quello che ti serve - Ho bisogno di aprire una nuova risposta per mostrare il codice formattato, ma l'essenza è più o meno la tua. –

1

Grazie! Sembra che il programma di Mark si comporta in modo diverso sotto CPython 2.5 e 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!" 

Emette (sotto 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! 

E:

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

Ecco la mia risposta, dal momento che Non riesco a vedere la conclusione nelle risposte precedenti.

Ho iniziato a chiedermi la stessa cosa e ho provato un programma di test che è simile a quelli di altre risposte e la mia conclusione è stata che ottengono GCed prima della fine del programma, il che significa che questi riferimenti possono essere determinati come spazzatura una volta che il filo stesso muore.

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) 

L'output:

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 

Come si può vedere, la cancellazione della sembrano accadere non appena il filo muore.

Problemi correlati