В частности, в Python, как переменные распределяются между потоками?
Хотя я использовал threading.Thread
раньше, я никогда по-настоящему не понимал и не видел примеров того, как разделяются переменные. Распространены ли они между основным потоком и детьми или только между детьми? Когда мне нужно будет использовать локальное хранилище потоков, чтобы избежать этого совместного использования?
Я видел много предупреждений о синхронизации доступа к общим данным между потоками с помощью блокировок, но мне еще предстоит увидеть действительно хороший пример проблемы.
Заранее спасибо!
Ответы:
В Python все является общим, за исключением локальных переменных функции (поскольку каждый вызов функции получает свой собственный набор локальных переменных, а потоки всегда являются отдельными вызовами функций). И даже тогда только сами переменные (имена, которые относятся к объектам) являются локальными для функции; сами объекты всегда глобальны, и на них может ссылаться что угодно. В этом отношении
Thread
объект для конкретного потока не является особым объектом. Если вы хранитеThread
объект где-нибудь, к которому имеют доступ все потоки (например, глобальная переменная), тогда все потоки могут получить доступ к этому одномуThread
объекту. Если вы хотите атомарно изменить что-либо , к чему другой поток имеет доступ, вы должны защитить это блокировкой. И все потоки, конечно же, должны использовать одну и ту же блокировку, иначе это будет не очень эффективно.Если вам нужно фактическое локальное хранилище потока, вот тут-то и
threading.local
пригодится. Атрибутыthreading.local
не используются совместно между потоками; каждый поток видит только те атрибуты, которые он там разместил. Если вам интересно узнать о его реализации, источник находится в _threading_local.py в стандартной библиотеке.источник
Рассмотрим следующий код:
Здесь threading.local () используется как быстрый и грязный способ передать некоторые данные из run () в bar () без изменения интерфейса foo ().
Обратите внимание, что использование глобальных переменных не поможет:
Между тем, если бы вы могли позволить себе передавать эти данные в качестве аргумента foo () - это был бы более элегантный и хорошо продуманный способ:
Но это не всегда возможно при использовании стороннего или плохо спроектированного кода.
источник
Вы можете создать локальное хранилище потоков, используя
threading.local()
.Данные, хранящиеся в tls, будут уникальными для каждого потока, что поможет предотвратить непреднамеренное совместное использование.
источник
Как и в любом другом языке, каждый поток в Python имеет доступ к одним и тем же переменным. Нет различия между «основным потоком» и дочерними потоками.
Одно отличие от Python заключается в том, что глобальная блокировка интерпретатора означает, что только один поток может запускать код Python одновременно. Однако это не очень помогает, когда дело доходит до синхронизации доступа, поскольку все обычные проблемы с упреждением по-прежнему актуальны, и вы должны использовать примитивы потоковой передачи, как и в других языках. Однако это означает, что вам нужно пересмотреть, использовали ли вы потоки для повышения производительности.
источник
Я могу ошибаться здесь. Если вы знаете иное, поясните, что это поможет объяснить, почему нужно использовать поток local ().
Это утверждение кажется неправильным, а не неправильным: «Если вы хотите атомарно изменить что-либо, к чему другой поток имеет доступ, вы должны защитить это блокировкой». Я думаю, что это утверждение -> эффективно <- верно, но не совсем точно. Я думал, что термин «атомарный» означает, что интерпретатор Python создает фрагмент байт-кода, который не оставляет места для сигнала прерывания для процессора.
Я думал, что атомарные операции - это куски байтового кода Python, которые не дают доступа к прерываниям. Такие операторы Python, как «running = True», атомарны. В этом случае вам не нужно блокировать процессор от прерываний (я считаю). Разбивка байтового кода Python защищена от прерывания потока.
Код Python, такой как «thread_running [5] = True», не является атомарным. Здесь есть два фрагмента байтового кода Python; один для отмены ссылки на list () для объекта и другой фрагмент байтового кода для присвоения значения объекту, в данном случае «место» в списке. Прерывание может быть вызвано -> между <- двумя байтовыми кодами -> фрагментами <-. Это были плохие вещи.
Как thread local () соотносится с "атомарным"? Вот почему это утверждение мне кажется неверным. Если нет, вы можете объяснить?
источник