多线程Flask应用导致rpy2 R进程出现栈错误

Multithreaded Flask application causes stack error in rpy2 R process

基本上与这里相同的错误,但这些解决方案没有提供足够的信息来复制一个工作示例:Rpy2 in a Flask App: Fatal error: unable to initialize the JIT

在我的 Flask 应用程序中,使用 rpy2.rinterface 模块,每当我初始化 R 时,我都会收到相同的堆栈使用错误:

import rpy2.rinterface as rinterface 
from rpy2.rinterface_lib import openrlib

with openrlib.rlock: 
    rinterface.initr()

Error: C stack usage 664510795892 is too close to the limit Fatal error: unable to initialize the JIT

rinterface是rpy2中底层的R hook,但是高层的robjects模块报同样的错误。我尝试在多处理模块的进程中包装上下文锁和 R 初始化,但有同样的问题。文档说多线程环境会给 R 带来问题:https://rpy2.github.io/doc/v3.3.x/html/rinterface.html#multithreading 但是上下文管理器似乎并没有阻止与 R

接口的问题

rlock 是 Python 的 threading.Rlock 的实例。它应该处理多线程问题。

但是,如果嵌入式 R 在子进程之间共享,则多处理可能会导致类似的问题。此演示脚本的代码显示了使用 R 和 Python 进程的并行处理说明了这一点:https://github.com/rpy2/rpy2/blob/master/doc/_static/demos/multiproc_lab.py

我认为解决这个问题的方法是配置 Flask,或者很可能是你的 wsgi 层,以创建独立的子进程,或者让你的所有 Flask 进程将 R 计算委托给辅助进程(动态创建,或者在等待任务执行的进程池中)。

正如其他类似问题的答案所暗示的那样,Flask 用户需要在 WSGI 上下文之外初始化和 运行 rpy2,以防止嵌入式 R 进程崩溃。我用 Celery 实现了这一点,其中工作人员提供了一个与 Flask 分开的环境来处理在 R 中发出的请求。

我使用了问题中提到的 low-level rinterface 库,并使用 类

编写了 Celery 任务
import rpy2.rinterface as rinterface
from celery import Celery

celery = Celery('tasks', backend='redis://', broker='redis://')

class Rpy2Task(Task):   
    def __init__(self):
        self.name = "rpy2"

    def run(self, args):    
        rinterface.initr()
        r_func = rinterface.baseenv['source']('your_R_script.R')
        r_func[0](args) 
        pass

Rpy2Task = celery.register_task(Rpy2Task())
async_result = Rpy2Task.delay(args)

工作人员在除任务 运行 主体以外的任何地方调用 rinterface.initr() 会导致上述崩溃。 Celery 通常与 redis 一起打包,我发现这是支持 R 和 Python 之间交换信息的有用方式,当然 Rpy2 也提供了灵活的方式来实现这一点。