Что такое "локальное хранилище потоков" в Python и зачем оно мне нужно?
в Python в частности, как переменные разделяются между потоками?
хотя я использовал threading.Thread
раньше я никогда не понимал и не видел примеров того, как переменные были разделены. Являются ли они общими между основной нитью и детьми или только между детьми? Когда мне нужно будет использовать локальное хранилище потоков, чтобы избежать этого совместного использования?
Я видел много предупреждений о синхронизации доступа к общим данным между потоками с помощью замков, но я еще не видел действительно хороший пример проблемы.
спасибо заранее!
4 ответа:
в Python все является общим, за исключением локальных переменных функции (потому что каждый вызов функции получает свой собственный набор локальных объектов, а потоки всегда являются отдельными вызовами функций.) И даже тогда только сами переменные (имена, которые ссылаются на объекты) являются локальными для функции; сами объекты всегда глобальны, и все может ссылаться на них. Элемент
Thread
объект для конкретного потока не является специальным объектом в этом отношении. Если вы хранитеThread
объект где-то все потоки может получить доступ (например, глобальная переменная), то все потоки могут получить доступ к этому
рассмотрим следующий код:
#/usr/bin/env python from time import sleep from random import random from threading import Thread, local data = local() def bar(): print("I'm called from", data.v) def foo(): bar() class T(Thread): def run(self): sleep(random()) data.v = self.getName() # Thread-1 and Thread-2 accordingly sleep(1) foo()
>> T().start(); T().start() I'm called from Thread-2 I'm called from Thread-1здесь тред.local() используется как быстрый и грязный способ передачи некоторых данных из run() в bar () без изменения интерфейса foo ().
обратите внимание, что использование глобальных переменных не будет делать трюк:
#/usr/bin/env python from time import sleep from random import random from threading import Thread def bar(): global v print("I'm called from", v) def foo(): bar() class T(Thread): def run(self): global v sleep(random()) v = self.getName() # Thread-1 and Thread-2 accordingly sleep(1) foo()
>> T().start(); T().start() I'm called from Thread-2 I'm called from Thread-2между тем, если бы вы могли позволить себе передать эти данные в качестве аргумента foo ()-это был бы более элегантный и хорошо продуманный способ:
from threading import Thread def bar(v): print("I'm called from", v) def foo(v): bar(v) class T(Thread): def run(self): foo(self.getName())
но это не всегда возможно при использовании стороннего или плохо разработанного кода.
вы можете создать локальное хранилище потоков с помощью
threading.local()
.>>> tls = threading.local() >>> tls.x = 4 >>> tls.x 4
данные, хранящиеся в tls, будут уникальны для каждого потока, что поможет гарантировать, что непреднамеренный обмен не произойдет.
Как и в любом другом языке, каждый поток в Python имеет доступ к тем же переменным. Нет никакого различия между основным потоком и потоками ребенок.
одно отличие от Python заключается в том, что глобальная блокировка интерпретатора означает, что только один поток может одновременно запускать код Python. Однако это не очень помогает, когда речь заходит о синхронизации доступа, поскольку все обычные проблемы с упреждением все еще применяются, и вам нужно использовать примитивы потоков, как и в других языки. Однако это означает, что вам нужно пересмотреть, если вы использовали потоки для производительности.