Problemas de bloqueo en Docker con rpy2 y R por uso de multithreading

Al desplegar aplicaciones en Docker que utilizan rpy2 para invocar funciones R con cálculos paralelos, se pueden encontrar bloqueos enesperados. Este artículo detalla un caso específico con la biblioteca WaveICA y proporciona una solución.

En un entorno donde Gradio se usa para construir una interfaz, ciertos algoritmos requieren R. Para mantener la consistencia entre desarrollo y producción, se emplea Docker. Sin embargo, al ejecutar una función R que utiliza mclapply para paralelismo, el proceso se detiene sin consumir CPU y la memoria no se libera. Al interrumpir con Ctrl+C, aparece el error:

*** longjmp causes uninitialized stack frame ***: terminated

Las búsquedas iniciales no arrojarno soluciones. Se probaron variaciones como cambiar imágenes Docker (de r-base a rocker/r-ver o ubuntu:22.04 con configuración manual), actualizar versiones de rpy2 o Gradio, y revisar problemas de kernel del host. Curiosamente, ejecutar el mismo código R directamente fuera de Docker funcionaba sin errores.

El avance llegó al examinar el código fuente de la función WaveICA_2.0. Se aisló un bucle que usa mclapply para ajustar modelos GAM en paralelo:

nivel <- 1
datos_wave_ICA <- list()
for (i in 1:nivel) {
    cat(paste("######### ICA", i, "#############\n"))
    coef_data <- coeficientes[[i]]
    coef_ICA <- unbiased_stICA(X=t(coef_data), k=K, alpha)
    B <- coef_ICA$B
    A <- coef_ICA$A
    B <- as.data.frame(B)
    
    # Ejecución paralela con mclapply
    correlaciones <- mclapply(B, function(col) {
        modelo <- gam(col ~ s(Orden_Inyeccion))
        resumen <- summary(modelo)
        r_cuadrado <- resumen$r.sq
        return(r_cuadrado)
    })
    correlaciones <- unlist(correlaciones)
    etiquetas <- which(correlaciones >= Corte)
    B_nuevo <- B[, etiquetas, drop=FALSE]
    A_nuevo <- A[, etiquetas, drop=FALSE]
    Xn <- datos_coef - t(A_nuevo %*% t(B_nuevo))
    datos_wave_ICA[[i]] <- Xn
}

La sugerencia clave fue reemplazar mclapply por lapply para evitar el paralelismo problemático en el contexto de rpy2 y Docker. La versión corregida del bucle sería:

correlaciones <- lapply(B, function(col) {
    modelo <- gam(col ~ s(Orden_Inyeccion))
    resumen <- summary(modelo)
    r_cuadrado <- resumen$r.sq
    return(r_cuadrado)
})

Al modificar directamente la función R para usar lapply en lugar de mclapply, el problema se resolvió. Esto sugiere que la interacción entre rpy2, Docker y el multithreading de R puede causar bloqueos, y que deshabilitar el paralelismo dentro del código R invocado desde Python es una solución viable.

Etiquetas: rpy2 Docker R Multithreading WaveICA

Publicado el 6-13 00:29