Вопрос:

Что такое «потоковое локальное хранилище» в Python и зачем оно мне нужно?

python multithreading thread-local

41805 просмотра

4 ответа

2298 Репутация автора

В частности, в Python, как переменные распределяются между потоками?

Хотя я использовал threading.Threadраньше, я никогда не понимал и не видел примеры того, как переменные стали общими. Распределяются ли они между основным потоком и детьми или только среди детей? Когда мне нужно будет использовать локальное хранилище потоков, чтобы избежать этого общего доступа?

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

Заранее спасибо!

Автор: Mike Источник Размещён: 19.09.2008 07:53

Ответы (4)


63 плюса

93028 Репутация автора

Решение

В Python все совместно используются, кроме локальных переменных функций (потому что каждый вызов функции получает свой собственный набор локальных переменных, а потоки всегда являются отдельными вызовами функций.) И даже тогда, только сами переменные (имена, которые относятся к объектам) являются локальными для функции; Сами объекты всегда глобальны, и что угодно может ссылаться на них. ThreadОбъект для конкретного потока не является особым объектом в этом отношении. Если вы храните Threadобъект где-то, к чему могут обращаться все потоки (например, глобальная переменная), тогда все потоки могут получить доступ к этому одному Threadобъекту. Если вы хотите атомарно изменить что-либочто вы не просто создали в этом же потоке, и не сохранили нигде другой поток может получить его, вы должны защитить его с помощью блокировки. И все потоки, конечно же, должны использовать одну и ту же блокировку, иначе она не будет очень эффективной.

Если вам нужно реальное локальное хранилище для потоков, вот где это threading.localпроисходит. Атрибуты threading.localне разделяются между потоками; каждый поток видит только те атрибуты, в которых он находится. Если вас интересует его реализация, источник находится в _threading_local.py в стандартной библиотеке.

Автор: Thomas Wouters Размещён: 19.09.2008 07:59

1 плюс

94774 Репутация автора

Как и в любом другом языке, каждый поток в Python имеет доступ к одним и тем же переменным. Там нет различий между «основным потоком» и дочерними потоками.

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

Автор: Nick Johnson Размещён: 19.09.2008 08:03

15 плюса

78375 Репутация автора

Вы можете создать локальное хранилище потоков используя threading.local().

>>> tls = threading.local()
>>> tls.x = 4 
>>> tls.x
4

Данные, хранящиеся в tls, будут уникальными для каждого потока, что поможет избежать непреднамеренного обмена.

Автор: Aaron Maenpaa Размещён: 20.09.2008 12:31

62 плюса

631 Репутация автора

Рассмотрим следующий код:

#/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 (); Т (). Начать ()
Меня зовут из Нити-2
Меня зовут из Нити-1 

Здесь threading.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 (); Т (). Начать ()
Меня зовут из Нити-2
Меня зовут из Нити-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())

Но это не всегда возможно при использовании стороннего или плохо разработанного кода.

Автор: ahatchkins Размещён: 12.12.2009 06:58
Вопросы из категории :
32x32