[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不再困扰其他人。