- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我们的 Web 应用程序充当集成层,允许用户运行 Matlab 代码(Matlab 是一种科学编程语言),该代码被编译为 Java,通过浏览器打包为 jar 文件(选定的如上图所示,除了remote_proxy-1.0.0.jar
不是,它用于 RMI)。
问题是,包含在 javabuilder-1.0.0.jar
文件内的 Matlab Java 运行时具有进程范围的阻塞机制,这意味着如果第一个用户发送 HTTP 请求来执行cdf_read-1.0.0.jar
或任何 Matlab 编译为 Java 的 jar 文件,则后续请求将阻塞,直到第一个请求完成,并且由于 JNI 已完成,因此将花费不少于 5 秒的时间用于调用 native Matlab 代码,并且因为应用程序服务器只是生成新线程来服务每个请求,但同样,由于 Matlab Java 运行时的进程范围锁定机制,这些新生成的线程将仅阻塞等待第一个请求来实现,因此我们的应用程序在技术上可以一次为一个用户提供服务。
因此,为了解决这个问题,对于每个此类请求,我们启动一个新的 JVM 进程,将请求发送到这个新进程以使用 RMI 运行作业,然后将结果返回到应用程序服务器的进程,然后销毁该进程产生的过程。所以我们已经解决了阻塞问题,但是就内存使用而言这根本不是很好,这是一个小众应用程序,因此用户数量在数千人范围内。下面是用于启动一个新进程来运行 BootStrap
类的代码,该类启动一个新的 RMI 注册表,并绑定(bind)一个远程对象来运行该作业。
package rmi;
import java.io.*;
import java.nio.file.*;
import static java.util.stream.Collectors.joining;
import java.util.stream.Stream;
import javax.enterprise.concurrent.ManagedExecutorService;
import org.slf4j.LoggerFactory;
//TODO: Remove sout
public class ProcessInit {
public static Process startRMIServer(ManagedExecutorService pool, String WEBINF, int port, String jar) {
ProcessBuilder pb = new ProcessBuilder();
Path wd = Paths.get(WEBINF);
pb.directory(wd.resolve("classes").toFile());
Path lib = wd.resolve("lib");
String cp = Stream.of("javabuilder-1.0.0.jar", "remote_proxy-1.0.0.jar", jar)
.map(e -> lib.resolve(e).toString())
.collect(joining(File.pathSeparator));
pb.command("java", "-cp", "." + File.pathSeparator + cp, "rmi.BootStrap", String.valueOf(port));
while (true) {
try {
Process p = pb.start();
pool.execute(() -> flushIStream(p.getInputStream()));
pool.execute(() -> flushIStream(p.getErrorStream()));
return p;
} catch (Exception ex) {
ex.printStackTrace();
System.out.println("Retrying....");
}
}
}
private static void flushIStream(InputStream is) {
try (BufferedReader br = new BufferedReader(new InputStreamReader(is))) {
br.lines().forEach(System.out::println);
} catch (IOException ex) {
LoggerFactory.getLogger(ProcessInit.class.getName()).error(ex.getMessage());
}
}
}
这个类用于启动一个新的RMI注册表,这样每个执行Matlab代码的HTTP请求都可以在一个单独的进程中运行,我们这样做的原因是因为每个RMI注册表都绑定(bind)到一个进程,所以我们需要一个单独的进程每个 JVM 进程的注册表。
package rmi;
import java.rmi.RemoteException;
import java.rmi.registry.*;
import java.rmi.server.UnicastRemoteObject;
import java.util.logging.*;
import remote_proxy.*;
//TODO: Remove sout
public class BootStrap {
public static void main(String[] args) {
int port = Integer.parseInt(args[0]);
System.out.println("Instantiating a task runner implementation on port: " + port );
try {
System.setProperty("java.rmi.server.hostname", "localhost");
TaskRunner runner = new TaskRunnerRemoteObject();
TaskRunner stub = (TaskRunner)UnicastRemoteObject.exportObject(runner, 0);
Registry reg = LocateRegistry.createRegistry(port);
reg.rebind("runner" + port, stub);
} catch (RemoteException ex) {
Logger.getLogger(BootStrap.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
此类允许提交执行 Matlab 代码的请求、返回结果并终止新生成的进程。
package rmi.tasks;
import java.rmi.*;
import java.rmi.registry.*;
import java.util.Random;
import java.util.concurrent.*;
import java.util.logging.*;
import javax.enterprise.concurrent.ManagedExecutorService;
import remote_proxy.*;
import rmi.ProcessInit;
public final class Tasks {
/**
* @param pool This instance should be injected using @Resource(name = "java:comp/DefaultManagedExecutorService")
* @param task This is an implementation of the Task interface, this
* implementation should extend from MATLAB class and accept any necessary
* arguments, e.g Class1 and it must implement Serializable interface
* @param WEBINF WEB-INF directory
* @param jar Name of the jar that contains this MATLAB function
* @throws RemoteException
* @throws NotBoundException
*/
public static final <T> T runTask(ManagedExecutorService pool, Task<T> task, String WEBINF, String jar) throws RemoteException, NotBoundException {
int port = new Random().nextInt(1000) + 2000;
Future<Process> process = pool.submit(() -> ProcessInit.startRMIServer(pool, WEBINF, port, jar));
Registry reg = LocateRegistry.getRegistry(port);
TaskRunner generator = (TaskRunner) reg.lookup("runner" + port);
T result = generator.runTask(task);
destroyProcess(process);
return result;
}
private static void destroyProcess(Future<Process> process) {
try {
System.out.println("KILLING THIS PROCESS");
process.get().destroy();
System.out.println("DONE KILLING THIS PROCESS");
} catch (InterruptedException | ExecutionException ex) {
Logger.getLogger(Tasks.class.getName()).log(Level.SEVERE, null, ex);
System.out.println("DONE KILLING THIS PROCESS");
}
}
}
问题:
最佳答案
rmiregistry.exe
。在默认端口上启动它并使用适当的 CLASSPATH,以便它可以找到它们所依赖的所有 stub 和应用程序类。runner%d
。您不需要多个注册表端口,甚至不需要多个注册表。
关于java - Matlab Java 互操作性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42233498/
我是一名优秀的程序员,十分优秀!