2

I have two Java Servlets: DataFetcherServlet and UploaderServlet. Both servlets call 2 different Java methods which in turn call their corresponding Matlab functions through JNI, and each of which was compiled into a separate Java jar file to use as a library. The application is powered by AJAX to create a Desktop like feel. For the UploaderServlet, the users can upload an excel file to this servlet, the parsed data then get passed to a Java method which then calls the compiled Matlab function to generate and save alot of images (currently over 5000 images), because this will take alot of time, I use an ExecutorService to execute it in the background. But new requests sent the DataFetcherServlet which will also call another compiled Matlab function is blocked until the image generation part is completed. I don't know why it is blocking new requests even though the requests are sent to a different 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);
        }
    }
}
Trash Can
  • 6,608
  • 5
  • 24
  • 38
  • Because main Matlab execution happens on a single thread? – nirvana-msu Aug 05 '16 at 22:50
  • Could possibly. We installed the matlab runtime on the server. But every user will be blocked while some matlab function is executing for some user – Trash Can Aug 08 '16 at 21:52
  • Yes, it will block other users. You either have to launch multiple Matlab instances (e.g. one per user) and route the commands appropriately, or else use something like [Matlab Production Server](http://uk.mathworks.com/products/matlab-production-server/) – nirvana-msu Aug 08 '16 at 21:56
  • Do you know how we could launch multiple Matlab instances? – Trash Can Aug 08 '16 at 22:03
  • How do you launch the first one? You have to launch and connect to it somehow. Just do the same multiple times? – nirvana-msu Aug 08 '16 at 22:04
  • We are not doing anything to launch the first one. We just installed Matlab Runtime SDK on our server. And we call the compiled matlab function from Java. We are not doing anything actually to call Matlab except for the fact that we packaged several matlab functions into each jar so we use them from Java – Trash Can Aug 08 '16 at 22:07
  • I missed your point that you are running an MCR, not Matlab itself. Please refer to the answer I provided. – nirvana-msu Aug 08 '16 at 22:50
  • What I meant was that, I just called the Java method generated by Matlab IDE, Matlab IDE compiles the function and packages it up into a jar so we can use it in Java, when we call this method, JNI will actually invoke the underlying Matlab function. So technically, we don't have any Matlab code in our Java code. – Trash Can Aug 09 '16 at 16:21

1 Answers1

2

You have three options:

  1. Launch multiple processes of your Java application that makes calls to Matlab. Calls from a single process use the same MCR which has a process-wide lock, however calls from different processes would run on separate MCR computational engines.
  2. Use Matlab Production Server, which basically facilitates the use of multiple MCRs. This is a toolkit that requires a separate license and installation.
  3. You don't necessarily have to limit yourself to running MCR / compiled code unless you have very specific performance concerns. You can actually install Matlab itself on the server, launch multiple instances (headless, etc) from the same Java process, and communicate with them e.g. through MatlabControl or the new official MATLAB Engine API for Java.

There's a very good answer from MathWorks Support Team on MatlabCentral, explaining these limitations of MCR in detail.

Community
  • 1
  • 1
nirvana-msu
  • 3,877
  • 2
  • 19
  • 28
  • 1
    Thank you very much for this. The fist option is not possible because we are running a web app, so creating so many processes for the smame user is going to kill the application because processes are memory heavy and we don't know how many users will be using the app at the same time. Second option, we can look into. Option 3 is the most viable one right now. I sincerely appreciate your help – Trash Can Aug 09 '16 at 16:31