为什么我不能同时从Java执行不同的Matlab函数?

时间:2016-07-19 20:04:24

标签: java matlab servlets matlab-compiler matlab-java

我有两个Java Servlet:DataFetcherServletUploaderServlet。两个servlet都调用两个不同的Java方法,这些方法又通过JNI调用它们相应的Matlab函数,并且每个方法都被编译成一个单独的Java jar文件用作库。该应用程序由AJAX提供支持,以创建类似桌面的感觉。对于UploaderServlet,用户可以将excel文件上传到此servlet,然后将解析后的数据传递给Java方法,然后调用已编译的Matlab函数生成并保存大量图像(当前超过5000个图像),因为这需要很多时间,我使用ExecutorService在后​​台执行它。但是发送DataFetcherServlet的新请求也将被阻止,这也将调用另一个已编译的Matlab函数,直到图像生成部分完成为止。即使将请求发送到不同的servlet,我也不知道为什么它会阻止新的请求。

DataFetcherServlet.java

public class DataFetcherServlet extends HttpServlet {

    @Inject
    private CdfReader reader; // An EJB to get a data array from Matlab

    protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
        try {
            String filePath = "path/to/file";
            Object[] result = reader.read(filePath); // reader.read() is just a wrapper around the method in the jar file mentioned above that actually calls the matlab function to return an array of number
            MWNumericArray array = (MWNumericArray)result[0] // This will block while the other Matlab function is generating the images.
            .
            .
            .
        } catch (MWException ex) {
            Logger.getLogger(DataFetcherServlet.class.getName()).log(Level.SEVERE, null, ex);
    }
}

UploaderServlet.java

public class UploaderServlet extends HttpServlet {
    @Inject
    private ExcelIonImageGenerator generator; // An EJB to call Matlab to generate the images

    protected void doPost(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
        try {
            String dir = "path/to/parent/directory";
            Path excel = Paths.get(dir+ "excel", part.getSubmittedFileName()); // Path to where the uploaded excel file is stored
            if (!Files.exists(excel))
                Files.copy(part.getInputStream(), excel);
            // ExcelExtractor is a helper class to parse the excel file.
            Double[][] ranges = ExcelExtractor.extractSheet(WorkbookFactory.create(excel.toFile()));
            // This will call a Java library method which in turns call the Matlab function
            // to generate the images (over 5000 in this case)
            // See the code for this method below.
            generator.generate(dir+ "images" + File.separator, ranges);
        } catch (MWException | InvalidFormatException ex) {
            Logger.getLogger(UploaderServlet.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

ExcelIonImageGenerator.java

import com.mathworks.toolbox.javabuilder.*; // Matlab SDK needed to integrate with Java
import java.util.concurrent.*;
import java.util.logging.*;
import javax.annotation.PreDestroy;
import javax.ejb.Stateless;
import save_ion_image_for_all_ranges_in_spreadsheet.Class1; // The jar file which contains code to call Matlab code through JNI

@Stateless
public class ExcelIonImageGenerator {
    private final Class1 clazz1;
    private ExecutorService pool;

    public ExcelIonImageGenerator() throws MWException {
        clazz1 = new Class1();
        pool = Executors.newFixedThreadPool(1);
    }

    public void generate(String path, Double[][] ranges) throws MWException {
        // Submit this task to the ExecutorService so it can be processed
        // in a different thread than the caller thread
        pool.submit(() -> generateHelper(path, ranges, clazz1), 1);
    }

    private void generateHelper(String path, Double[][] ranges, Class1 clazz) {
        try {
            // This method was generated by Matlab tool, it calls the native
            // Matlab code through JNI, and it will block any request that will call
            // other Matlab functions until it finishes.
            clazz.save_ion_image_for_all_ranges_in_spreadsheet(path, ranges);
        } catch (MWException ex) {
            Logger.getLogger(ExcelIonImageGenerator.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

1 个答案:

答案 0 :(得分:2)

您有三种选择:

  1. 启动调用Matlab的Java应用程序的多个进程。来自单个进程的调用使用具有进程范围锁定的相同MCR,但来自不同进程的调用将在单独的MCR计算引擎上运行。
  2. 使用Matlab Production Server,这基本上有助于使用多个MCR。这是一个需要单独许可和安装的工具包。
  3. 除非您有非常具体的性能问题,否则您不一定要限制自己运行MCR /编译代码。您实际上可以在服务器上安装Matlab本身,从同一个Java进程启动多个实例(无头等),并与它们通信,例如通过MatlabControl或新官方MATLAB Engine API for Java
  4. 在MatlabCentral上有一个非常好的answer from MathWorks Support Team,详细解释了MCR的这些局限性。