При интервьюировании недавно, меня часто просили реализовать структуру данных, обычно LinkedList или HashMap. Оба из них достаточно легки быть выполнимыми в скором времени и достаточно трудными устранить невежественное.
Марк был почти прав - по сути, «mydata» будет содержать ссылки на все переменные TL, из какого бы потока они ни были созданы. То есть ...:
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!"
Излучает:
t created
t started
x got deleted!
mydata deleted
t joined
Done!
gc фактически не играет здесь роли в CPython, поэтому вы можете упростить код до:
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!"
и при этом увидеть ...:
t created
x got created!
t started
x got deleted!
mydata deleted
t joined
Done!
Спасибо! Похоже, что программа Марка ведет себя по-разному в CPython 2.5 и 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!"
Выдает (в 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!
И:
Python 2.6.2 (r262:71600 Sep 19 2009 17:24:20)
t created
t started
x got deleted!
mydata deleted
t joined
Done!
Внеся пару простых изменений в вашу программу и принудительно запустив сборку мусора после каждого шага потоковой передачи, кажется, что foo
не может быть собран, пока программа не будет завершена - другими словами, после поток выходит из области видимости.
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!"
вывод (с использованием Python 2.6, Windows):
>C:\temp\py\t.py t created t started t joined Done! x got deleted!
Вот мой ответ, поскольку я не вижу вывода в предыдущих ответах.
Мне стало интересно то же самое, и я попробовал тестовую программу, которая похожа на те, что были в других ответах, и я пришел к выводу, что они действительно собираются в сборку раньше, чем конец программы, что означает, что эти ссылки могут быть определены как мусор. как только сама нить умирает.
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)
Результат:
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
Как видите, удаление происходит, как только поток умирает.