[Debug日记] rpy2与R中的多线程与docker的奇妙反应

关键词rpy2, docker, 多线程
琐碎生活中遇到了复杂的奇怪需求,套娃带来的奇妙反应,这就是胶水语言吗?

TLDR

docker内,使用rpy2调用R的并行计算方法会失去响应。

场景

基于gradio快速构建前端应用时,该应用的部分算法基于R,因此需要使用rpy2来调用相应的R函数。为了维持开发环境和部署环境的R和python包一致,选择使用docker来部署,但也因此遇到了问题,具体代码如下:

ro.r('''
library("WaveICA2.0")
''')
# Pandas DataFrame转换为R DataFrame
with localconverter(ro.default_converter + pandas2ri.converter):
    # print(type(data))
    data_r = ro.conversion.py2rpy(data)
    injection_order_r = ro.conversion.py2rpy(injection_order)
# 调用R中的WaveICA函数
with conversion.localconverter(default_converter + pandas2ri.converter):
    result_r = ro.r['WaveICA_2.0'](data_r, wf=wf, Injection_Order=injection_order_r, alpha=alpha, Cutoff=cutoff, K=K)

当执行WaveICA_2.0函数时,函数的ICA部分会在执行不定数量的循环后停止运行(观察CPU和内存占用可知,不再占用CPU,但内存并未释放),如果Ctrl+C结束程序会提示错误:

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

Google这个问题几乎没有解决方案。以下是无法走通的道路:

  • 直接google错误,相关的内容最多的以curl多线程下载为主;
  • 检索docker+错误信息没有可用的,与上一条没有太大区别;
  • 从rpy2来考虑。在21年的github issue中提到了类似的错误信息,但这里是在python中启动多线程,且issue提到相关的问题已经被修复;
  • 更改gradio、rpy2的版本没有效果;
  • 使用不同的docker镜像没有效果。最初使用r-base:4.3.2,但该镜像总是使用最新的debian,因此换成rocker/r-ver:4.3.2,该镜像基于ubuntu 22.04,但仍有相同问题;最终使用原始的ubuntu:22.04镜像从头配置R和python环境,仍不可用。
  • 怀疑docker的宿主机内核导致的,但同一镜像的宿主机尝试了WSL、MAC和Ubuntu,也是相同错误。
  • 在原始R代码中执行相同的函数,正常运行,没有报错;

突破点:

  • WaveICA_2.0有另外的1.0版本,即WaveICA,通过rpy2调用该版本是可以正常运行的;
    考虑到循环总是卡在这部分,就掏出相应循环到源码给GPT-4o来帮我debug:
index<-level+1
data_wave_ICA<-list()
for (i in (1:index)){
  cat(paste("######### ICA",i,"#############\n"))
  data_coef<-coef[[i]]
  data_coef_ICA<-unbiased_stICA(X=t(data_coef),k=K,alpha)
  B <- data_coef_ICA$B
  A <- data_coef_ICA$A

  B <- as.data.frame(B)

  ## Gam
  corr <- mclapply(B,function(x){
    corr <- gam(x~s(Injection_Order))
    corr_summary <- summary(corr)
    corr_r <- corr_summary$r.sq
    return(corr_r)
  })
  corr <- unlist(corr)
  label <- which(corr>=Cutoff)
  B_new <- B[,label,drop=F]
  A_new <- A[,label,drop=F]
  Xn = data_coef-t(A_new %*% t(B_new))

  data_wave_ICA[[i]]<-Xn
}

而GPT-4o的回答第一条就指出了关键:

并行计算问题

你在代码中使用了mclapply函数,这个函数用于并行计算。如果你的系统不支持并行计算,或者并行计算的设置不正确,可能会导致代码卡住。你可以尝试将mclapply替换为lapply,看看是否能解决问题:

corr <- lapply(B, function(x){
  corr <- gam(x ~ s(Injection_Order))
  corr_summary <- summary(corr)
  corr_r <- corr_summary$r.sq
  return(corr_r)
})

是的,并行计算与前面多线程的使用不谋而合。因此直接修改该函数的源码而不是直接使用相应的library就解决了这个问题。
希望这个奇怪的bug不再困扰其他人。

posted @ 2024-06-28 15:29  myweihp  阅读(14)  评论(0编辑  收藏  举报