问题描述
与这里的错误基本上相同,但是这些解决方案没有提供足够的信息来复制一个有效的示例: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钩子,但较高级的robjects模块给出相同的错误。我尝试从多处理模块中将上下文锁和R初始化包装在Process中,但是存在相同的问题。医生说多线程环境会给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完成的,在Celery中,工作人员提供了与Flask分开的环境来处理R中的请求。
我使用了问题中提到的低级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当然也提供了灵活的方法。