Локальный атрибут потока, определенный глобально, недоступен в потоках - PullRequest
0 голосов
/ 06 мая 2020
import threading


threadlocal = threading.local()
threadlocal.depth = 0


def _increase_depth():
    threadlocal.depth += 1


def _decrease_depth():
    threadlocal.depth -= 1


def _use_it():
    print(threadlocal.depth)

Но я получаю:

AttributeError: '_thread._local' object has no attribute 'depth'

То, что я ожидал: каждый поток получает depth, инициализированный 0, и изменения будут видны только в этом конкретном потоке.

Почему атрибуты, определенные в threadlocal, недоступны в потоках?

(Этот код работает в разработке с тестовым сервером django: я еще не адаптировал его для создания минимального примера что может быть продемонстрировано с помощью простых потоков)

Ответы [ 2 ]

1 голос
/ 06 мая 2020

Что я ожидал: каждый поток получает depth, инициализированный как 0

Это не так, как это работает. Только поток, который создал вашу глобальную переменную threadlocal, установил depth в 0. Предположительно основной поток. Вы должны инициализировать значение в каждом потоке отдельно.

0 голосов
/ 06 мая 2020

Эта реализация решает мои проблемы:

import threading

_INDENT = '   '

_threadlocal = threading.local()
_defaults = dict(depth=0, prefix='')


class ThreadLocal:

    _initialized = False  # This allows us to set / get attributes during __init__

    def __init__(self, thread_data, defaults=None):
        self._thread_data = thread_data
        self._defaults = defaults or {}
        self._initialized = True

    def __setattr__(self, key, value):
        if self._initialized:
            setattr(self._thread_data, key, value)
        else:
            # Allow setting attributes in __init__
            self.__dict__[key] = value

    def __getattr__(self, item):
        if self._initialized:
            return getattr(self._thread_data, item, _defaults.get(item))
        else:
            # Allow getting attributes in __init__
            return self.__dict__[item]


threadlocal = ThreadLocal(_threadlocal, _defaults)


def _increase_depth():
    threadlocal.depth += 1
    threadlocal.prefix = _INDENT * threadlocal.depth


def _decrease_depth():
    threadlocal.depth -= 1
    threadlocal.prefix = _INDENT * threadlocal.depth
...