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

Respuesta

3

Mark tenía casi la derecha - esencialmente "misdatos" puede contener referencias a todas las variables TL en el mismo, cualquiera que sea el hilo que fueron creados de. A saber ...:

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

Emite:

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

gc realidad no juega ningún papel aquí en CPython, por lo que puede simplificar el código 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!" 

sin dejar de ver ...:

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

Al hacer un par de cambios simples en su programa y obligando a una recolección de basura después de cada paso de la rosca, parece que foo no se pueden recoger hasta que el programa ha terminado - en otras palabras, después el hilo se apaga de alcance

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

salida (usando Python 2.6, Windows):

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

Buen análisis, pero lo que falta es que _mydata_ va a desaparecer es lo que necesita - Necesito abrir una nueva respuesta para mostrar el código formateado, pero la esencia es muy similar a la suya. –

1

Gracias! Parece que el programa de Mark se comporta de manera diferente bajo CPython 2.5 y 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!" 

Se emite (bajo 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! 

Y:

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

aquí está mi respuesta, ya No veo la conclusión en las respuestas anteriores.

Empecé a preguntarme lo mismo y probé un programa de prueba que es similar a los de otras respuestas y mi conclusión fue que sí reciben GCed antes que el final del programa, lo que significa que estas referencias se pueden determinar como basura una vez que el hilo muere.

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 salida:

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 

Como se puede ver, la eliminación de parecen ocurrir tan pronto como el hilo muere.

Cuestiones relacionadas