python haskell asynchronous exception-handling

¿Tiene Python un equivalente a las funciones de "máscara" o "corchete" de Haskell?



asynchronous exception-handling (1)

En Haskell tenemos excepciones asincrónicas; podemos usar throwTo para plantear cualquier excepción en otro hilo:

throwTo :: Exception e => ThreadId -> e -> IO ()

throwTo genera una excepción arbitraria en el hilo de destino (solo GHC).

Para poder escribir código con garantías como "siempre lanzará un bloqueo después de adquirirlo", tenemos mask para ejecutar código en el que solo se pueden recibir excepciones asincrónicas mientras el cálculo está bloqueando:

mask :: ((forall a. IO a -> IO a) -> IO b) -> IO b

Ejecuta un cálculo de IO con excepciones asíncronas enmascaradas . Es decir, cualquier hilo que intente generar una excepción en el hilo actual con throwTo será bloqueado hasta que las excepciones asincrónicas vuelvan a desenmascararse.

y un más fuerte uninterruptibleMask en el cual las excepciones asincrónicas no se levantarán en absoluto durante un cálculo enmascarado:

uninterruptibleMask :: ((forall a. IO a -> IO a) -> IO b) -> IO b

Como mask , pero el cálculo enmascarado no es interrumpible

El enmascaramiento se usa para implementar abstracciones de mayor nivel como el bracket :

bracket :: IO a -- computation to run first ("acquire resource") -> (a -> IO b) -- computation to run last ("release resource") -> (a -> IO c) -- computation to run in-between -> IO c -- returns the value from the in-between computation

Cuando desee adquirir un recurso, trabaje con él y luego libere el recurso, es una buena idea usar el bracket , ya que bracket instalará el manejador de excepción necesario para liberar el recurso en caso de que se produzca una excepción durante el cálculo. Si se produce una excepción, el bracket volverá a generar la excepción (después de realizar el lanzamiento).

Si entiendo correctamente, Python tiene una forma (menos general) de excepciones asincrónicas, con la manifestación más notable es KeyboardInterrupt :

Se genera cuando el usuario pulsa la tecla de interrupción (normalmente Control - C o Eliminar ). Durante la ejecución, se realiza un control de interrupciones con regularidad.

La documentación es imprecisa sobre cuándo puede producirse la "comprobación de interrupciones", pero parece implicar que una KeyboardInterrupt puede surgir en cualquier punto de la ejecución de un programa. Entonces, parece que las excepciones asíncronas de Python tienen todas las mismas sutiles dificultades para mantener la corrección.

Por ejemplo, considere un patrón como este:

x = None try: x = acquire() do_something(x) # (1) finally: if x is not None: # (2) release(x)

Si se produce alguna excepción durante (1) , se nos garantiza que se ejecutará el contenido del bloque finally . ¿Pero qué sucede si un KeyboardInterrupt está durante (2) ?

Parece fundamentalmente imposible garantizar la limpieza de recursos en presencia de excepciones asyc sin una forma de enmascararlas. ¿Hay alguna facilidad para esto, o confiamos en el algoritmo de avestruz ?


Para esto están los administradores de contexto.

with acquire() as x: do_something(x)

acquire devuelve un objeto cuyo tipo define un método __enter__ , que devuelve el valor vinculado a x , y un método __exit__ , que se ejecuta al final de la instrucción with , independientemente de cómo se abandona la declaración.