我有两个 Java Servlet:DataFetcherServlet
和 UploaderServlet
。两个 servlet 都调用 2 个不同的 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);
}
}
}
最佳答案
您有三个选择:
- 启动 Java 应用程序的多个进程来调用 Matlab。来自单个进程的调用使用具有进程范围锁的相同 MCR,但是来自不同进程的调用将在单独的 MCR 计算引擎上运行。
- 使用Matlab Production Server ,这基本上方便了多个MCR的使用。这是一个需要单独许可和安装的工具包。
- 除非您有非常具体的性能问题,否则您不必限制自己运行 MCR/编译代码。您实际上可以在服务器上安装 Matlab 本身,从同一个 Java 进程启动多个实例( headless 等),并与它们通信,例如通过MatlabControl或者新官方MATLAB Engine API for Java .
有一个非常好的answer from MathWorks Support Team在 MatlabCentral 上,详细解释了 MCR 的这些局限性。
关于java - 为什么我不能同时从 Java 执行不同的 Matlab 函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38467526/