使用 Wildfly 9 从 Spring MVC 运行 Rscript [英] Run Rscript from Spring MVC with Wildfly 9

查看:18
本文介绍了使用 Wildfly 9 从 Spring MVC 运行 Rscript的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试从 JAVA 代码运行 Rscript.我有能力这样做.现在我正在尝试从 Spring MVC 项目运行相同的 JAVA 代码并使用 Wildfly 9 运行该项目.第一次当我尝试执行 JAVA 代码(运行 Rscript)时工作正常并给出正确的结果,但是在第二次运行时它给出错误并且 Wildfly 停止运行.以下是我收到的错误:

I am trying to run Rscript from JAVA code. I am able to do so. Now I am trying to run same JAVA code from a Spring MVC project and using Wildfly 9 to run the project. For the first time when I am trying to execute JAVA code (to run Rscript) is working fine and giving correct result, but on running 2nd time it is giving error and Wildfly stops running. Below is the error that I am getting:

A fatal error has been detected by the Java Runtime Environment:
Internal Error (0xc0000029), pid=6768, tid=8456
JRE version: Java(TM) SE Runtime Environment (7.0_75-b13) (build 1.7.0_75-b13)
Java VM: Java HotSpot(TM) Client VM (24.75-b04 mixed mode, sharing windows-x86 )
Problematic frame:
C  [ntdll.dll+0xa096a]
Failed to write core dump. Minidumps are not enabled by default on client versions of Windows

JAVA 代码如下:

package com.test.util;

import org.rosuda.JRI.Rengine;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class RunRScript {
private static final Logger logger = LoggerFactory
        .getLogger(RunRScript.class);

public void runScript() {
    // Create an R vector in the form of a string.
    String javaVector = "c(1,2,3,4,5)";

    // Start Rengine.
    Rengine engine = new Rengine(new String[] { "--no-save" }, false, null);

    // The vector that was created in JAVA context is stored in 'rVector' which is a variable in R context.
    engine.eval("rVector=" + javaVector);

    //Calculate MEAN of vector using R syntax.
    engine.eval("meanVal=mean(rVector)");

    //Retrieve MEAN value
    double mean = engine.eval("meanVal").asDouble();

    //Print output values
    logger.info("Mean of given vector is=" + mean);        
}
}

我使用的是 Windows 8 64 位和 R-2.15.0.如果我的问题不清楚或者您需要任何其他信息,请告诉我.提前致谢.

I am using Windows 8 64-bit and R-2.15.0. Please let me know if my question is not clear or you need any other information. Thanks in advance.

推荐答案

您不能使用该代码调用 JRI 引擎.根据文档,JRI 不允许每个 JVM 超过一个引擎实例,因此您不应创建多个引擎.

You can't call JRI engine with that code. According to the documentation, JRI doesn't allow more that one engine instance per JVM, so you shouldn't create more than one engine.

这一行:

// Start Rengine.
Rengine engine = new Rengine(new String[] { "--no-save" }, false, null);

只能调用一次.您必须确保在您的 JVM 中只启动一个引擎.

Must be called only once. You have to ensure that only one engine is started in your JVM.

另一方面,JRI 默认使用相同的环境来处理所有调用(eval、assign 等...),因此您的其余代码必须同步,否则每次两个不同的调用都会遇到竞争条件线程正在执行 eval 方法.

On the other hand, JRI uses by default the same environment to handle all the calls (eval, assign, etc...) so the rest of your code must be synchronized, otherwise you can suffer race conditions every time two different threads are executing eval methods.

如果您无法正常工作,可以将 JRI 替换为 Rserve,这不需要将 JRI 库加载到 JVM 中并允许并发(每个线程必须使用自己的 RConnection).

If you have trouble getting it working, you can replace JRI by Rserve, that doesn't need JRI library loaded into the JVM and allow concurrency (each thread must use its own RConnection).

但是对于 Rserve,您应该只设置一次引擎,并且使用 JRI.

But with Rserve you should setup your engine only once, as well as using JRI.

您可以使用@PostConstruct 方法:

You can use a @PostConstruct method:

/**
 * This method initializes REngine properly and make all the operations needed 
 * to set up the environment.
 * 
 * This RServe implementation must run R in a separate process and check the connection.
 * 
 */
@PostConstruct
public void setUpR() {//NOSONAR

    REngine engine = null;
    try {
        if(LOGGER.isInfoEnabled()) {
            LOGGER.info("Starting RServe process...");
        }
        ProcessBuilder builder = new ProcessBuilder("/bin/sh", "-c", String.format("echo 'library(Rserve);Rserve(FALSE,args=\"--no-save --slave --RS-conf %s\")'|%s --no-save --slave", rserveConf, rexe));
        builder.inheritIO();
        Process rProcess = builder.start();

        if(LOGGER.isInfoEnabled()) {
            LOGGER.info("Waiting for Rserve to start...");
        }
        int execCodeResult = rProcess.waitFor();

        if(execCodeResult != SUCCESS_CODE) {
            LOGGER.error(String.format("Unexpected error code starting RServe: %d", execCodeResult));
        } else {
            LOGGER.error("RServe started successfully");
        }

        if(LOGGER.isInfoEnabled()) {
            LOGGER.info("Opening connection to RServe daemon....");
        }
        engine = new RConnection();
        if(LOGGER.isInfoEnabled()) {
            LOGGER.info(String.format("Obtaining R server version: %d", ((RConnection)engine).getServerVersion()));
        }

    } catch(Exception e) {
        LOGGER.error("Unexpected error setting up RServe environment", e);
    } finally {
        closeRServeConnection(engine);
    }
}

你可以用 JRI 做同样的事情:

You can do the same with JRI:

/**
 * This method initializes REngine properly and make all the operations needed 
 * to set up the environment.
 * 
 * This JRI implementation must load JRI library and starts JRIEngine
 * 
 */
@PostConstruct
public void setUpR() {//NOSONAR

    try {
        //make sure JRI lib can be loaded (it must be present in java.library.path parameter)
        //This line is necessary because Rengine.versionCheck() will execute a System.exit if
        //it can't load JRI library.
        System.loadLibrary("jri");
        // just making sure we have the right version of everything
        if (!Rengine.versionCheck()) {
            LOGGER.error("** Version mismatch - Java files don't match library version.");
            LOGGER.error(String.format("Invalid versions. Rengine must have the same version of native library. Rengine version: %d. RNI library version: %d", Rengine.getVersion(), Rengine.rniGetVersion()));
        }

        // Enables debug traces
        Rengine.DEBUG = 1;

        if(LOGGER.isInfoEnabled()) {
            LOGGER.info("Creating Rengine (with arguments)");
        }
        // 1) we pass the arguments from the command line
        // 2) we won't use the main loop at first, we'll start it later
        // (that's the "false" as second argument)
        // 3) no callback class will be used
        this.engine = REngine.engineForClass("org.rosuda.REngine.JRI.JRIEngine", new String[] { "--no-save" }, new REngineStdOutCallback(LOGGER), false);
        if(LOGGER.isInfoEnabled()) {
            LOGGER.info("Rengine created...");
            LOGGER.info("Loading blockFunction from " + getBlockFunction());
        }

        REXP result = engine.parseAndEval(getBlockFunction());
        if(result == null) {
            LOGGER.error("blockFunction is not loaded!");
        } else if(LOGGER.isInfoEnabled()) {
            LOGGER.info("blockFunction loaded successfully");
        }
    } catch(Exception|UnsatisfiedLinkError e) {
        LOGGER.error("Unexpected error setting up R", e);
    }
}

然后在每次调用中重用相同的 Rengine 实例(确保同步访问此实例).

And then reuse the same Rengine instance in each call (make sure you synchronize the access to this instance).

您在这个 repo

这篇关于使用 Wildfly 9 从 Spring MVC 运行 Rscript的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆