Uso seguro de datos compartidos
Use colas y bloqueos
Uso seguro de datos compartidos es una lección gratuita de Python Academy en CoddyKit. Esta es la lección 4 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de Python Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de Python Academy incluye 4 lecciones en total.
El problema de las condiciones de carrera
Cuando varios hilos modifican los mismos datos, sus operaciones pueden intercalarse y corromper el resultado. Esto es una condición de carrera. Necesitamos herramientas de sincronización para compartir datos de forma segura.
import threading
counter = 0
def bump():
global counter
for _ in range(100000):
counter += 1
ts = [threading.Thread(target=bump) for _ in range(2)]
for t in ts: t.start()
for t in ts: t.join()
print('counter (may be < 200000):', counter)El bloqueo al rescate
Un threading.Lock garantiza que solo un hilo entre en una sección crítica cada vez. Adquiéralo con un bloque with alrededor de la actualización compartida.
import threading
counter = 0
lock = threading.Lock()
def bump():
global counter
for _ in range(100000):
with lock:
counter += 1
ts = [threading.Thread(target=bump) for _ in range(2)]
for t in ts: t.start()
for t in ts: t.join()
print('counter:', counter)acquire y release
Un bloqueo se puede utilizar manualmente con acquire() y release(), pero la forma with es más segura porque lo libera incluso si se produce un error.
import threading
lock = threading.Lock()
lock.acquire()
try:
print('inside critical section')
finally:
lock.release()
print('released')Colas seguras para hilos
La clase queue.Queue ya es segura para hilos. Los hilos pueden hacer put y get sin bloqueos explícitos, por lo que es la forma preferida de pasar datos.
import queue, threading
q = queue.Queue()
def producer():
for i in range(3):
q.put(i)
t = threading.Thread(target=producer)
t.start()
t.join()
while not q.empty():
print('got', q.get())Productores y consumidores
El patrón clásico: los productores introducen trabajo en una cola con put, y los consumidores lo obtienen y procesan con get. La cola gestiona todos los bloqueos.
import queue, threading
q = queue.Queue()
results = []
def consumer():
while True:
item = q.get()
if item is None:
break
results.append(item * 10)
q.task_done()
t = threading.Thread(target=consumer)
t.start()
for i in range(3):
q.put(i)
q.put(None)
t.join()
print(results)join y task_done
q.join() se bloquea hasta que cada elemento que se ha introducido con put ha tenido una llamada correspondiente a task_done(). Esto permite que el hilo principal espere a que termine todo el trabajo.
import queue, threading
q = queue.Queue()
def worker():
while True:
item = q.get()
q.task_done()
threading.Thread(target=worker, daemon=True).start()
for i in range(5):
q.put(i)
q.join()
print('all items processed')RLock para la reentrancia
Un Lock normal provoca un interbloqueo si el mismo hilo intenta adquirirlo dos veces. Un threading.RLock (bloqueo reentrante) lo permite y contabiliza las adquisiciones.
import threading
rlock = threading.RLock()
def outer():
with rlock:
inner()
def inner():
with rlock:
print('re-entered safely')
outer()Event para señalización
Un threading.Event permite que un hilo envíe una señal a otros. Los hilos llaman a wait() hasta que otro llama a set().
import threading
start = threading.Event()
def worker():
start.wait()
print('go!')
t = threading.Thread(target=worker)
t.start()
print('setting event')
start.set()
t.join()Compartir entre procesos
Entre procesos, utilice multiprocessing.Queue. Serializa objetos entre espacios de memoria independientes.
import multiprocessing as mp
def producer(q):
for i in range(3):
q.put(i * i)
if __name__ == '__main__':
q = mp.Queue()
p = mp.Process(target=producer, args=(q,))
p.start()
p.join()
while not q.empty():
print('received', q.get())Cómo evitar interbloqueos
Un interbloqueo ocurre cuando los hilos esperan indefinidamente los bloqueos de los demás. Evítelo adquiriendo siempre varios bloqueos en el mismo orden en todas partes.
import threading
lock_a = threading.Lock()
lock_b = threading.Lock()
def safe():
with lock_a:
with lock_b:
print('acquired in consistent order')
safe()Prefiera las colas a los bloqueos
Cuando sea posible, prefiera el paso de mensajes mediante colas al estado mutable compartido protegido por bloqueos. Es más fácil de comprender y mucho menos propenso a errores.
import queue
q = queue.Queue()
for word in ['safe', 'simple', 'clear']:
q.put(word)
while not q.empty():
print(q.get())Comprobación rápida
Compruebe su comprensión del uso compartido seguro de datos.
Resumen
Ha aprendido a compartir datos de forma segura:
- Las condiciones de carrera corrompen el estado compartido no protegido.
LockyRLockprotegen las secciones críticas.queue.Queuees segura para hilos; utilicemultiprocessing.Queueentre procesos.Eventpermite enviar señales entre hilos; un orden coherente de adquisición de bloqueos evita los interbloqueos.
Siguiente curso: ejecutar programas externos con subprocess.
Preguntas frecuentes
¿La lección «Uso seguro de datos compartidos» es gratis?
Sí — el texto completo de «Uso seguro de datos compartidos» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de Python Academy, actualiza a CoddyKit PRO. El curso de Python Academy incluye 4 lecciones en total.
¿Qué aprenderé en «Uso seguro de datos compartidos»?
Use colas y bloqueos Practicas Python Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.
¿Necesito experiencia previa para empezar Python Academy?
No se requiere experiencia previa. Python Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 4 de 4.
¿Cuánto tiempo toma la lección «Uso seguro de datos compartidos»?
La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.
¿Puedo escribir y ejecutar código en esta lección de Python Academy?
Sí. Cada lección de Python Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.
Todas las lecciones de este curso
- Hilos y el GIL
- ThreadPoolExecutor
- Conceptos básicos de multiprocessing
- Uso seguro de datos compartidos