Каково время жизни локального для потока значения в Python?

При интервьюировании недавно, меня часто просили реализовать структуру данных, обычно LinkedList или HashMap. Оба из них достаточно легки быть выполнимыми в скором времени и достаточно трудными устранить невежественное.

8
задан Carlos Valiente 25 September 2009 в 16:16
поделиться

4 ответа

Марк был почти прав - по сути, «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!
3
ответ дан 5 December 2019 в 15:25
поделиться

Спасибо! Похоже, что программа Марка ведет себя по-разному в 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!
1
ответ дан 5 December 2019 в 15:25
поделиться

Внеся пару простых изменений в вашу программу и принудительно запустив сборку мусора после каждого шага потоковой передачи, кажется, что 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!
0
ответ дан 5 December 2019 в 15:25
поделиться

Вот мой ответ, поскольку я не вижу вывода в предыдущих ответах.

Мне стало интересно то же самое, и я попробовал тестовую программу, которая похожа на те, что были в других ответах, и я пришел к выводу, что они действительно собираются в сборку раньше, чем конец программы, что означает, что эти ссылки могут быть определены как мусор. как только сама нить умирает.

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

Как видите, удаление происходит, как только поток умирает.

7
ответ дан 5 December 2019 в 15:25
поделиться
Другие вопросы по тегам:

Похожие вопросы: