python - tipos de bloqueo comunes

1 cerradura ordinaria Lock/RLock (cerradura de exclusión mutua)

        Los subprocesos comparten recursos en el mismo proceso y es fácil competir por los recursos y generar datos sucios . El papel del mutex es resolver el problema de la contención de recursos , permitiendo que una determinada parte del recurso sea accedida por un solo subproceso al mismo tiempo. Nota : Intente usar mutexes cuando acceda a recursos públicos.

        1.1 Bloquear bloqueo original

         El candado se denomina candado original y no se emite ningún juicio antes de adquirir el candado hasta que se adquiere el candado.

        1.1.1Método de instancia Lock()

        1 adquirir () : intenta adquirir un bloqueo. Haga que el subproceso entre en el estado de bloqueo síncrono.

        2 release() : libera el bloqueo, el subproceso debe haber adquirido el bloqueo antes de su uso, de lo contrario, se lanzará una excepción.

        1.1.2 Caja pequeña

import threading
import time
num=0
# def add_num(i):
#     lock.acquire()
#     global num
#     time.sleep(1)
#     num += i
#     print(f"num is {num}")
#     lock.release()

def add_num(i):
    # 使用with语句管理对象 -- 上下文管理器对象
    # 上下文管理器对象  __enter__,  __exit__
    # __enter__方法做一些初始化工作
    # __exit__方法做一些结束收尾工作  释放资源
    with lock:
        global num
        time.sleep(1)
        num += i
        print(f"num is {num}")


t_list = []

# 生成一个锁实例
lock = threading.Lock()
for i in range(10):
    t = threading.Thread(target=add_num, args=(i,))
    t.start()
[t.join() for t in t_list]

print("ending......")

        1.1.3 Fenómeno de interbloqueo

        Si usa Bloqueo (bloqueo original) , en el mismo proceso, después de adquirir el bloqueo original, el bloqueo no se ha liberado e intenta adquirir el mismo bloqueo original, se producirá un fenómeno de interbloqueo. Sin embargo, se usa RLock (bloqueo de reentrada) Debido a que juzgará si ha adquirido el bloqueo, generalmente no causa interbloqueo.

        1.2 Bloqueo reentrante RLock

        RLock se llama bloqueo reentrante, juzgue antes de adquirir el bloqueo, si tiene el bloqueo, regrese inmediatamente

        1.2.1 Caja pequeña

import threading
lock1 = threading.Lock()
lock2 = threading.RLock()

# 这种情况会产生死锁
# lock1.acquire()
# print("lock1 acqurie 1")
# lock1.acquire()  # 同一个进程,获取原始锁之后,没有释放又去尝试获取同一个 原始锁,就会产生死锁
# print("lock1 acquire 2")
# lock1.release()
# print("lock1 release 1")
# lock1.release()
# print("lock1 release 2")

lock2.acquire()
print("lock2 acqurie 1")
lock2.acquire()
print("lock2 acquire 2")
lock2.release()
print("lock2 release 1")
lock2.release()
print("lock2 release 2")

        Este código refleja bien las similitudes y diferencias entre Lock y RLock.


2 semáforo (Semáforo)

        Los bloqueos de semáforo permiten que hasta N subprocesos ejecuten contenido al mismo tiempo.

        2.1 Método de construcción

        Semaphore(N) : s = threading.Semaphore(N) crea un objeto de bloqueo de semáforo. N es un parámetro entero , lo que significa establecer el límite superior de subprocesos que se pueden ejecutar al mismo tiempo.

        2.2 Métodos de instancia

        adquirir () : intenta adquirir un bloqueo, lo que hace que el subproceso entre en un estado de bloqueo síncrono.

        release() : Libera el bloqueo. El subproceso debe haber adquirido el bloqueo antes de usarlo , de lo contrario, se lanzará una excepción.


bloqueo de 3 eventos

        Mecanismo de evento: se define globalmente una " Bandera " , que se denomina bit de bandera. Si el valor del bit indicador es False , cuando el programa ejecute wait(), se bloqueará; si el valor del bit indicador es True , entonces el método wait() ya no se bloqueará. Nota: los bloqueos de eventos no se pueden usar con la declaración with, pero solo se pueden usar de la manera habitual.

        Este tipo de bloqueo es similar a los semáforos (el valor predeterminado es la luz roja) , pertenece a bloquear todos los subprocesos al mismo tiempo cuando la luz está en rojo y liberar todos los subprocesos en cola al mismo tiempo cuando la luz está en verde.

        El evento es uno de los mecanismos para la comunicación entre subprocesos: un subproceso envía una señal de evento y otros subprocesos esperan esta señal. Es decir, el hilo principal controla la ejecución de otros hilos .

        3.1 Método de construcción

        Event() : e = threading.Event() genera un objeto de bloqueo de evento

        3.2 Métodos de instancia

        e.wait([tiempo de espera]) : Bloquee el hilo hasta que el indicador interno del objeto Evento se establezca en Verdadero o tiempo de espera, aquí puede elegir establecer el parámetro de tiempo de espera.

        set() : Establece el bit de bandera en True .

        clear() : Establece el bit de bandera en False .

        isSet() : determina si la bandera es True .


4 bloqueos condicionales 

        Este mecanismo hará que los hilos esperen, y solo cuando se cumpla una determinada condición, se liberarán n hilos .

        4.1 Método de construcción

        Condición() : c = enhebrar.condición()

        4.2 Métodos de instancia

        wait_for(func) : Espere a que la función devuelva el resultado, si el resultado es Verdadero, libere un hilo

       wait(), c.notify(N) : libera N esperas a la vez

        adquirir() :          liberar bloqueo() : desbloquear

        Las funciones wait y wait_for() anteriores deben usarse en medio del bloqueo y desbloqueo


5 Resumen de los bloqueos anteriores

        1 Los bloqueos de eventos se basan en bloqueos condicionales. La diferencia entre ellos y los bloqueos condicionales es que solo se pueden liberar todos a la vez, y cualquier número de subprocesos no se puede liberar para continuar ejecutándose.

        2 Los bloqueos de semáforo también se basan en bloqueos condicionales. Las diferencias entre ellos y los bloqueos condicionales y los bloqueos de eventos son las siguientes:

             2.1 El bloqueo condicional puede liberar cualquier número de subprocesos en el estado de "espera" a la vez.

             2.2 El bloqueo de eventos puede liberar todos los subprocesos en el estado de "espera" al mismo tiempo.

             2.3 Los bloqueos de semáforo , a través de regulaciones, liberan hilos específicos en el estado "bloqueado" en lotes. 

        3 Los bloqueos de eventos se basan internamente en bloqueos condicionales

        4 El bloqueo de semáforo interno también se basa en bloqueos condicionales


6 Bloqueo de intérprete global GIL

        La abreviatura en inglés de Global Interpreter Lock es GIL (Global Interpreter Lock). GIL no tiene nada que ver con el lenguaje Python. Es solo un problema que queda en el intérprete oficialmente recomendado CPython debido a razones históricas. ¿Por qué CPython todavía se recomienda oficialmente? Porque la comunidad de CPython es muy activa y tiene una biblioteca muy rica . Cada subproceso necesita obtener GIL primero durante la ejecución para garantizar que solo un subproceso pueda ejecutar código a la vez .

Solo hay dos comportamientos básicos de         GIL : 1. El subproceso que se está ejecutando actualmente contiene el GIL 2. Cuando el subproceso encuentra un bloqueo de E/S, liberará el GIL.

        Debido a la limitación del bloqueo de CIL, los subprocesos múltiples no son adecuados para tareas informáticas, pero son más adecuados para tareas de E/S.

        Las tareas intensivas en computación son cálculos frecuentes por parte de la CPU; las tareas intensivas en E/S son E/S de red (captura de datos de red), operaciones de disco (lectura y escritura de archivos), entrada de teclado, etc.

        Tareas computacionalmente intensivas --> usar múltiples procesos

        Tareas con uso intensivo de E/S --> utilizar subprocesos múltiples


 

Supongo que te gusta

Origin blog.csdn.net/m0_53891399/article/details/131523276
Recomendado
Clasificación