Локальное хранилище потоков в Python (threading.local)

Локальное хранилище потоков в Python (threading.local)

@python_quiz

Разберем этот квиз

Короткий заголовок: Поведение threading.local при доступе из разных потоков

Условие — код из квиза

python

Нужно понять, что напечатает этот фрагмент и почему.

Что делает код — пошагово

  • Создаётся объект local() — это специальный контейнер, который предоставляет отдельные наборы атрибутов для каждого потока.
  • В главном (основном) потоке задаётся storage.x = 0.
  • Создаётся и запускается новый поток, в котором в целевой функции читается storage.x через getattr(storage, 'x', 'no x'). Если атрибут x отсутствует в контексте этого потока, возвращается строка 'no x'.
  • После завершения потока (join) главный поток печатает storage.x.

Как работает threading.local

  • Объект local хранит значения атрибутов отдельно для каждого потока. Атрибут, установленный в одном потоке, не виден в другом.
  • Поэтому установка storage.x = 0 в главном потоке не автоматически создаёт x в новом потоке.

Ожидаемый вывод

При выполнении кода будет напечатано сначала то, что вернул getattr в потоке, а затем значение в главном потоке. Конкретно:

text

Первой строкой выводится 'no x' (поток не видит storage.x), затем 0 (значение, установленное в главном потоке).

Разбор вариантов ответов (почему некоторые варианты неверны)

  • "Сначала 0, потом 0" — неверно. Это предполагало бы, что атрибуты local разделяются *не* по потокам, и новое значение видимо в дочернем потоке. На самом деле дочерний поток не получает атрибуты из главного.
  • "Оба раза будет 'no x'" — неверно. Главный поток явно установил storage.x = 0, поэтому при печати в главном потоке будет 0.
  • "Сначала 'no x', потом 0" — соответствует поведению threading.local: дочерний поток не видит x, а главный поток печатает своё значение.
  • "Сначала 0, потом 'no x'" — неверно: сначала дочерний поток не видит x, поэтому он не сможет напечатать 0.

Дополнительный пример — показать изоляцию для двух потоков

Ниже пример, где каждый поток устанавливает своё значение x, чтобы увидеть, что они не мешают друг другу:

python

Ожидаемый вывод (порядок печати потоков может меняться):

text

Здесь видно: каждый поток имеет своё поле x, а главный поток не видит их значения.

Вывод

threading.local обеспечивает изолированные наборы атрибутов для каждого потока. Если установить атрибут в одном потоке, другие потоки не увидят это значение, пока сами не установят свой собственный атрибут. В рассматриваемом фрагменте дочерний поток не найдёт x и вернёт дефолт 'no x', а главный поток напечатает своё значение 0.

Report Page