threading - ¿Qué es "almacenamiento local de subprocesos" en Python, y por qué lo necesito?
threading python ejemplos (4)
En Python específicamente, ¿cómo se comparten las variables entre los hilos?
Aunque he usado el threading.Thread
Lo he threading.Thread
antes, nunca entendí realmente ni vi ejemplos de cómo se compartieron las variables. ¿Se comparten entre el hilo principal y los niños o solo entre los niños? ¿Cuándo necesitaré usar el almacenamiento local de subprocesos para evitar compartir?
He visto muchas advertencias sobre la sincronización del acceso a datos compartidos entre hilos mediante el uso de bloqueos, pero aún no he visto un buen ejemplo del problema.
¡Gracias por adelantado!
Al igual que en cualquier otro idioma, cada hilo en Python tiene acceso a las mismas variables. No hay distinción entre el ''hilo principal'' y los hilos secundarios.
Una diferencia con Python es que el bloqueo de intérprete global significa que solo un hilo puede ejecutar código Python a la vez. Sin embargo, esto no es de mucha ayuda cuando se trata de sincronizar el acceso, ya que todos los problemas de prioridad preferentes se siguen aplicando, y debe usar primitivas de subprocesamiento como en otros idiomas. Sin embargo, significa que debe reconsiderar si estaba utilizando subprocesos para el rendimiento.
Considera el siguiente código:
#/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
Aquí threading.local () se usa como una forma rápida y sucia de pasar algunos datos de run () a bar () sin cambiar la interfaz de foo ().
Tenga en cuenta que usar variables globales no hará el truco:
#/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
Mientras tanto, si pudiera permitirse pasar esta información como un argumento de foo (), sería una forma más elegante y bien diseñada:
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())
Pero esto no siempre es posible cuando se usa un código de terceros o mal diseñado.
En Python, todo se comparte, excepto las variables de función local (porque cada llamada de función obtiene su propio conjunto de locales, y los hilos son siempre llamadas de funciones separadas). Y aun así, solo las variables mismas (los nombres que se refieren a los objetos) son locales para la función; los objetos mismos son siempre globales, y cualquier cosa puede referirse a ellos. El objeto Thread
para un hilo en particular no es un objeto especial a este respecto. Si almacena el objeto Thread
alguna parte a la que todos los hilos puedan acceder (como una variable global), entonces todos los hilos pueden acceder a ese único objeto Thread
. Si quieres modificar atómicamente cualquier cosa que no hayas creado en este mismo hilo, y no lo hayas almacenado en otro lugar, puedes protegerlo con un bloqueo. Y todos los hilos deben, por supuesto, compartir este mismo bloqueo, o no sería muy efectivo.
Si desea un almacenamiento de hilo local real, ahí es donde entra threading.local
. Los atributos de threading.local
no se comparten entre hilos; cada hilo ve solo los atributos que él mismo colocó allí. Si tiene curiosidad acerca de su implementación, la fuente se encuentra en _threading_local.py
en la biblioteca estándar.
Puede crear un almacenamiento local de threading.local()
utilizando threading.local()
.
>>> tls = threading.local()
>>> tls.x = 4
>>> tls.x
4
Los datos almacenados en tls serán únicos para cada hilo, lo que ayudará a garantizar que no se produzca el intercambio involuntario.