Почему я не могу одновременно выполнять разные функции Matlab из Java?

У меня есть два Java-сервлета: DataFetcherServlet а также UploaderServlet, Оба сервлета вызывают 2 разных метода Java, которые в свою очередь вызывают соответствующие им функции Matlab через JNI, и каждый из них был скомпилирован в отдельный файл jar Java для использования в качестве библиотеки. Приложение работает на AJAX для создания ощущения рабочего стола. Для UploaderServletпользователи могут загрузить файл Excel в этот сервлет, затем проанализированные данные передаются в метод Java, который затем вызывает скомпилированную функцию Matlab для генерации и сохранения большого количества изображений (в настоящее время более 5000 изображений), поскольку это займет много времени Я использую ExecutorService выполнить его в фоновом режиме. Но новые запросы отправили DataFetcherServlet которая также будет вызывать другую скомпилированную функцию Matlab, будет заблокирована, пока не будет завершена часть создания изображения Я не знаю, почему он блокирует новые запросы, даже если запросы отправляются другому сервлету.

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 ответ

Решение

У вас есть три варианта:

  1. Запустите несколько процессов вашего Java-приложения, которое вызывает Matlab. Вызовы из одного процесса используют ту же MCR, которая имеет блокировку всего процесса, однако вызовы из разных процессов будут выполняться на отдельных вычислительных механизмах MCR.
  2. Используйте Matlab Production Server, который в основном облегчает использование нескольких MCR. Это инструментарий, для которого требуется отдельная лицензия и установка.
  3. Вам не обязательно ограничивать себя в запуске MCR / скомпилированного кода, если только у вас нет особых проблем с производительностью. На самом деле вы можете установить сам Matlab на сервер, запустить несколько экземпляров (без заголовка и т. Д.) Из одного и того же процесса Java и обмениваться данными с ними, например, через MatlabControl или новый официальный API-интерфейс MATLAB Engine для Java.

Существует очень хороший ответ от команды поддержки MathWorks на MatlabCentral, подробно объясняющий эти ограничения MCR.

Другие вопросы по тегам