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() 

Répondre

3

Mark avait presque droit - essentiellement "mydata" va contenir des références à toutes les variables de TL en elle, quel que soit fil ils ont été créés de. À savoir ...:

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

Emet:

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

gc joue effectivement aucun rôle dans CPython, de sorte que vous pouvez simplifier le code jusqu'à:

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

et encore voir ...:

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

En faisant un couple de simples changements à votre programme et en forçant une collecte des ordures après chaque étape du filetage, il semble que foo ne peuvent être collectées jusqu'à ce que le programme soit terminé - autrement dit, après le fil sort de portée.

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

sortie (en utilisant Python 2.6, Windows):

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

Bonne analyse, mais le bit manquant est que _mydata_ s'en va est ce que vous avez besoin - J'ai besoin d'ouvrir une nouvelle réponse pour afficher le code formaté, mais l'essentiel est le même que le vôtre. –

1

Merci! Il semble que le programme de Mark se comporte différemment dans CPython 2.5 et 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!" 

Emet (sous 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! 

Et:

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

Voici ma réponse, puisque Je ne parviens pas à voir la conclusion dans les réponses précédentes. J'ai commencé à me poser la même question et j'ai essayé un programme de test similaire à ceux des autres réponses, et je suis arrivé à la conclusion que les tests sont effectués plus tôt que la fin du programme, ce qui signifie que ces références peuvent être déterminées déchets une fois le fil meurt lui-même.

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) 

La sortie:

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 

Comme vous pouvez le voir, la supprimer de semblent se produire dès que le fil meurt.

Questions connexes