¿Cómo puedo mejorar el mecanismo de bloqueo de asyncio?
A continuación se muestra mi código en el que he implementado el mecanismo de bloqueo asyncio que debe bloquear una solicitud en el método si la solicitud con el mismo nombre ya está en ejecución y aún no se ha completado, lo cual funciona correctamente, pero el problema es que si la solicitud viene con un nombre diferente también se bloquea, lo cual no es ideal, idealmente debería ser que si la solicitud viene con un nombre de solicitud diferente debería comenzar su ejecución sin tener que esperar.
import asyncio
from contextlib import asynccontextmanager
@asynccontextmanager
async def get_lock(req_name_):
locks = {}
logger.info(f"Creando bloqueo para la pila {req_name_} si no está creado")
if not locks.get(req_name_):
logger.info("creando clave para un bloqueo")
locks[req_name_] = asyncio.Lock()
async with locks[req_name_]:
yield
if len(locks[req_name_]._waiters) == 0:
del locks[req_name_]
logger.info("bloqueo liberado")
logger.info(len(locks))
async def handle_lock_request(req_json_):
logger.info("ocupando bloqueo")
req_name = req_json_.get('req_name')
async with get_lock(req_name):
logger.info(f"bloqueo adquirido por la pila {req_name}")
await _handle_request(req_json_)
async def _req_handler():
tasks = []
loop = asyncio.get_running_loop()
logger.debug("Await receiver.recv_string")
req = await receiver.recv_string()
logger.debug(f"Solicitud recibida {req}")
req_json = json.loads(req)
logger.debug("Await create_task")
tasks.append(loop.create_task(handle_lock_request(req_json)))
await asyncio.gather(*[task for task in tasks if not task.done()])
def _handle_request(req_json_):
# ...
# ...
logger.info(f"Solicitud finalizada con nombre de solicitud {req_name} para la acción patch stack")
davy.ai
El problema con el código es que la variable
locks
está definida dentro de la funciónget_lock
y es una variable local. Esto significa que cada vez que se llama aget_lock
, se crea un nuevo diccionariolocks
.Para solucionar el problema,
locks
debería ser definido fuera de la funciónget_lock
para que sea una variable compartida en todas las llamadas aget_lock
.Aquí tienes una versión actualizada del código:
Con este cambio, el diccionario
locks
ahora es compartido en todas las llamadas aget_lock
, lo que significa que las solicitudes con diferentes nombres no serán bloqueadas por el bloqueo de una solicitud diferente.