从 Java 执行 julia 脚本

execute julia scripts from Java

我正在使用 ZeroMQ 编写 Julia 脚本。

我的目标是在两个脚本之间与 ZMQ 通信。这是一个例子:

# script1
using ZMQ
ctx = ZMQ.Context()
sockDealer = ZMQ.Socket(ctx, DEALER)
ZMQ.set_identity(sockDealer, "idA")
ZMQ.connect(sockDealer, "tcp://localhost:5555")
ZMQ.send(sockDealer, "hello world!")
ZMQ.close(sockDealer)
ZMQ.close(ctx)



#script2
using ZMQ

function pollrecv(socket::ZMQ.Socket,zmsg::Message)
  rc = -1
  while true
    rc = ccall((:zmq_msg_recv, ZMQ.zmq), Cint, (Ptr{Message}, Ptr{Void}, Cint),
                    &zmsg, socket.data, ZMQ.ZMQ_DONTWAIT)
  if rc == -1
    # Base.Libc.EAGAIN = 11
    # Problem unsolved: Failure to find Base.Libc.EAGAIN
    if !(ZMQ.zmq_errno() == 11)
      throw(ZMQ.StateError(ZMQ.jl_zmq_error_str()))
    end
    return false
    else
      ZMQ.get_events(socket) != 0 && notify(socket)
      break
    end
  end
  return true
end

ctx = ZMQ.Context()
sockRouter = ZMQ.Socket(ctx, ROUTER)
ZMQ.bind(sockRouter, "tcp://*:5555")
fini = false
while !fini
  println("listening...")
  idSock = Message()
  while pollrecv(sockRouter, idSock)
    msg = ZMQ.recv(sockRouter)
    println("msg recv: " * bytestring(msg))
    fini = true
  end
  sleep(1)
end
ZMQ.close(sockRouter)
ZMQ.close(ctx)

我可以在命令提示符下使用 Julia 执行它们。一切顺利。脚本2可以接收到脚本1的消息。

现在,我需要从 Java 执行它们。这意味着我需要创建一个类似于控制器的 java 项目。这是我的 Java 项目:

public class Container {

    private Vector<String[]> commands;

    public Container() {
        this.commands = new Vector<String[]>();
    }

    public void addCommand(String[] strs) {
        this.commands.addElement(strs);
    }

    public void execute() {
        for(int i = 0; i < this.commands.size(); i++) {
            try {
                Process p = Runtime.getRuntime().exec(this.commands.get(i));
                if(p.waitFor() != 0){
                    System.err.println("exit value = " + p.exitValue());
                }
                BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()));
                StringBuffer stringBuffer = new StringBuffer();
                String line = null;
                while((line = in.readLine()) != null){
                    stringBuffer.append(line + "-");
                }
                System.out.println(stringBuffer.toString());

            } catch (IOException ex) {
                // TODO Auto-generated catch block
                ex.printStackTrace();
            } catch(InterruptedException e){
                System.err.println(e);
            }
        }
    }
}


//main
public class Main {
    public static void main(String[] args) {
        Container c = new Container();

        String[] script1 = {"/usr/bin/julia", "/home/thomas/Julia/script1.jl"};
        String[] script2 = {"/usr/bin/julia", "/home/thomas/Julia/script2.jl"};
        c.addCommand(script1);
        c.addCommand(script2);
        c.execute();
    }
}

然而,当我 运行 我的 java 项目时,我可以看到它保持 运行ning 但我在控制台上看不到任何东西:没有结果,没有消息, 没有报错。

我认为我的 java 项目有问题。

您需要同时 运行 这两个脚本:script2 是服务器脚本,所以当您 运行 [=15] 时它应该是 运行ning =].现在,Process.waitFor() 将等待客户端脚本 script1 完成,然后在下一个 for 迭代中执行服务器脚本 script2

您可以这样启动它们:

    String[] clientScript = { "/usr/bin/julia", "/home/thomas/Julia/script1.jl" };
    String[] serverScript = { "/usr/bin/julia", "/home/thomas/Julia/script2.jl" };

    Process server = Runtime.getRuntime().exec(serverScript);
    Process client = Runtime.getRuntime().exec(clientScript);

并实例化两个线程以读取它们的输出:

    (new ProcessReader(server)).start();
    (new ProcessReader(client)).start();

使用

public class ProcessReader extends Thread {
    private Process p;

    public ProcessReader(Process p) {
        this.p = p;
    }

    @Override
    public void run() {
        BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()));
        try {
            String line;
            while ((line = in.readLine()) != null) {
                System.out.println("Read: " + line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

不过,由于 clientScript 不产生任何输出,您可以 启动脚本,只读取服务器脚本的输出——不需要线程。

还有一件事需要考虑:在 clientScript 尝试连接之前,serverScript 必须是 listening...。所以你可能想这样做:

    Process server = Runtime.getRuntime().exec(serverScript);
    BufferedReader in = new BufferedReader(new InputStreamReader(server.getInputStream()));
    if ( in.readLine().equals("listening...") ) {
        Process client = Runtime.getRuntime().exec(clientScript);

        String line;
        while ( (line=in.readLine()) != null )
            System.out.println("Read: " + line );
    }

由于这不是您问题的具体答案,这可能对您或其他尝试类似工作的用户有所帮助。

JuliaCaller 是用于从 Java 调用 Julia 的早期库。它将 Julia 可执行文件作为 Java 进程执行,并在 Julia 端执行 运行s 脚本。此脚本打开一个侦听给定端口号的 TCP 服务器。然后执行从 Java 发送的每个命令、语句或表达式,并将结果以 JSON 格式发送回 Java。

该库还实现了标准 javax.script 接口,这意味着 Julia 库、函数和程序可以 运行 像在 Java 中实现的脚本语言(模仿) .

示例如下:

Constants.setProperties(Constants.JULIA_PATH, "/usr/local/bin/julia");
Constants.setProperties(Constants.JULIA_PORT, "8001");

// Creating a scripting interface for Julia
manager = new ScriptEngineManager();
engine = manager.getEngineByName("Julia");

// Sending command 'a = 3' to Julia from Java
engine.eval("a = 3");

// Handling the result in Java
Object a = engine.get("a");

GitHub 页面中提供了更多示例。

Source code with Apache License