[英]Run Python script through Java with importing just once
Update April 2020 : I have accepted the answer below because it proposes a very good and simple solution to my problem but I never got my code to work! 2020 年 4 月更新:我接受了下面的答案,因为它为我的问题提出了一个非常好的和简单的解决方案,但我的代码从来没有工作过! If anyone has already built something similar please contact me!
如果有人已经建立了类似的东西,请联系我!
I have a simple script my-script.py
that does some calculations very fast using a specific library written in Python
:我有一个简单的脚本
my-script.py
使用Python
编写的特定库非常快速地进行一些计算:
import sys
import special-library
def fun(x):
do something
fun(sys.argv[1])
In my Java
code, I use/call this script a lot in different part of the code, using the ProcessBuilder
approach, which means that I simply run the command python my-script.py argument
.在我的
Java
代码中,我在代码的不同部分使用/调用此脚本很多,使用ProcessBuilder
方法,这意味着我只需运行命令python my-script.py argument
。 This means that every time I call this script, I have to execute the import
commands which is the most time-consuming thing in this (the calculation part is actually faster).这意味着每次我调用这个脚本时,我都必须执行
import
命令,这是其中最耗时的事情(计算部分实际上更快)。
Is there a solution so that I call the import just once ?有没有办法让我只调用一次导入? I looked a little bit about
Jython
- would be possible to write a class or something that would be initiated and do the import once and then calling a function of it every time I want to do the calculations part ( fun
)?我看了一点关于
Jython
的信息 - 是否可以编写 class 或一些可以启动并执行一次导入然后每次我想做计算部分时调用它的 function 的东西( fun
)? Has anyone done something similar or have any other solution to this?有没有人做过类似的事情或有任何其他解决方案?
I've tried to write a 'pipe' Java Class that will execute the python script once.我试图编写一个“管道” Java Class 将执行 python 脚本一次。 Now the script reads continuously from the stdin and when it gets an input
argument
, it does the calculations and returns the result:现在脚本从标准输入连续读取,当它获得输入
argument
时,它会进行计算并返回结果:
import sys
import special-library
def fun(x):
do something
print('END')
for arg in sys.stdin:
fun(arg)
And this works of course when I test it from the command line and supplying it with input arguments.当我从命令行对其进行测试并为其提供输入 arguments 时,这当然有效。
The Java Class is as follows: Java Class如下:
package my.package;
import java.io.*;
public class PythonScriptExecuter {
private static BufferedReader pythonToJavaReader;
private static PrintWriter javaToPythonWriter;
public PythonScriptExecuter() throws Exception {
String MPBNScriptFile = "fullPathToScriptFile";
ProcessBuilder pb = new ProcessBuilder("python", MPBNScriptFile);
pb.redirectErrorStream(true);
// Start script
Process p = pb.start();
pythonToJavaReader = getOutputReader(p); // from python to java
javaToPythonWriter = getInputWriter(p); // from java to python
}
// Python => Java
private static BufferedReader getOutputReader(Process p) {
return new BufferedReader(new InputStreamReader(p.getInputStream()));
}
// Java => Python
private static PrintWriter getInputWriter(Process p) {
return new PrintWriter(new OutputStreamWriter(p.getOutputStream()));
}
public static Arraylist<String> getResults(String argument) throws IOException {
// send argument to python script
javaToPythonWriter.println(argument);
//javaToPythonWriter.flush();
// get results back one by one
ArrayList<String> results = new ArrayList<>();
int count = 0;
String line;
while (!(line = pythonToJavaReader.readLine()).equals("END")) {
// process `line` string
results.add(line);
}
return results;
}
}
So, what I do is that somewhere in the initialization part of my code I have this simple line to start the process:所以,我所做的是在我的代码的初始化部分的某个地方,我有这个简单的行来启动这个过程:
new MPBNPythonScriptExecuter();
and later when I want to get some results back, I use:后来当我想得到一些结果时,我使用:
String arg = "something"
Arraylist<String> res = PythonScriptExecuter.getResults(arg);
and the whole thing hangs on the reading-the-output-from-the-script line:整个事情都挂在从脚本读取输出的行上:
while (!(line = pythonToJavaReader.readLine()).equals("END"))
Any ideas what is going wrong here?任何想法这里出了什么问题?
You could communicate between java and Python with pipes.您可以使用管道在 java 和 Python 之间进行通信。
You run your Python as you do now (without command line args)您像现在一样运行 Python(没有命令行参数)
Python script Python 脚本
you write an infinite loop in python that will您在 python 中编写了一个无限循环,它将
read data from the standard input (it will be your arg for the function)从标准输入读取数据(这将是函数的参数)
You call your function你打电话给你的 function
you write the answer to the standard output你写下标准 output 的答案
Java Java
Write a method for sending args to python编写发送args到python的方法
write to the pipe the arg of your function将 function 的 arg 写入 pipe
read the answer from the pipe从 pipe 中阅读答案
You're done.你完成了。
Here is some snippet这是一些片段
Here how you create your tube在这里你如何创建你的管
Process p = Runtime.getRuntime().exec(commande);
BufferedReader output = getOutput(p); //from python to java
BufferedReader error = getError(p); //from python to java
PrintWriter input = getInput(p); //from java to python
private static BufferedReader getOutput(Process p) {
return new BufferedReader(new InputStreamReader(p.getInputStream()));
}
private static BufferedReader getError(Process p) {
return new BufferedReader(new InputStreamReader(p.getErrorStream()));
}
private static PrintWriter getInput(Process p){
return new PrintWriter (new OutputStreamWriter(p.getOutputStream()));
}
Try the following in your Python script:在您的 Python 脚本中尝试以下操作:
import sys
def fun(x):
print(x)
print('END')
sys.stdout.flush()
while 1:
try:
line = sys.stdin.readline()
except KeyboardInterrupt:
break
if not line:
break
fun(line)
Your Java code should be more or less correct.您的 Java 代码应该或多或少是正确的。
I did a similar project.我做了一个类似的项目。 The options we had was Jython, Jep, graalVM and socket technology.
我们的选择是 Jython、Jep、graalVM 和套接字技术。 Indeed, I have never tested Jython because I need to call numpy which is not possible.
事实上,我从未测试过 Jython,因为我需要调用 numpy,这是不可能的。 Jep looks promising but you have to build it for specific version, and I could not make it work.
Jep 看起来很有希望,但你必须为特定版本构建它,我无法让它工作。 GraalVM is very nice, however It did not exist at that time and (it is not available for windows, but don't worry you can make the binary) and it is still experimental feature.
GraalVM 非常好,但是它当时并不存在并且(它不适用于 windows,但不用担心你可以制作二进制文件)并且它仍然是实验性功能。 So the only option was sockets technology.
所以唯一的选择是 sockets 技术。 you can easily make a socket in java, and likewise in python.
您可以轻松地在 java 中制作插座,同样在 python 中制作插座。 Then write a set of function to convert string to primitive arrays and wise versa.
然后编写一组 function 将字符串转换为原始 arrays ,反之亦然。 The drawback is needing compilation against your machines python and the time for communications.
缺点是需要针对您的机器 python 和通信时间进行编译。 I put the project on git, I hope you will find it useful.
我把项目放在git上,希望对你有用。
the Project's repo: https://github.com/amirshamaei/HLSVDPro4J项目的回购: https://github.com/amirshamaei/HLSVDPro4J
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.