通过Java运行Python脚本,只导入一次

通过Java运行Python脚本,只导入一次,java,python,import,jython,Java,Python,Import,Jython,2020年4月更新:我接受了下面的答案,因为它为我的问题提供了一个非常好且简单的解决方案,但我的代码从未运行过!如果有人已经建立了类似的东西,请与我联系 我有一个简单的脚本my script.py,它使用Python编写的特定库快速执行一些计算: 导入系统 导入专用库 def fun(x): 做点什么 乐趣(sys.argv[1]) 在我的Java代码中,我使用ProcessBuilder方法在代码的不同部分大量使用/调用此脚本,这意味着我只需运行命令python my-script.py参

2020年4月更新:我接受了下面的答案,因为它为我的问题提供了一个非常好且简单的解决方案,但我的代码从未运行过!如果有人已经建立了类似的东西,请与我联系


我有一个简单的脚本
my script.py
,它使用
Python
编写的特定库快速执行一些计算:

导入系统 导入专用库 def fun(x): 做点什么 乐趣(sys.argv[1]) 在我的
Java
代码中,我使用
ProcessBuilder
方法在代码的不同部分大量使用/调用此脚本,这意味着我只需运行命令
python my-script.py参数
。 这意味着每次调用此脚本时,我都必须执行
import
命令,这是其中最耗时的命令(计算部分实际上更快)

是否有一个解决方案以便我只调用导入一次?我看了一点关于
Jython
-是否可以编写一个类或什么东西,启动导入一次,然后每次我想做计算部分时调用它的函数(
fun
)?有没有人做过类似的事情或有其他解决方法

实施的第一次尝试 我试图编写一个“pipe”Java类,它将执行python脚本一次。现在,脚本不断地从stdin读取数据,当它获得一个输入
参数时,它进行计算并返回结果:

导入系统 导入专用库 def fun(x): 做点什么 打印('结束') 对于sys.stdin中的arg: 乐趣(arg)
当然,当我从命令行测试它并为它提供输入参数时,这是有效的

Java类如下所示:

package my.package;
导入java.io.*;
公共级蟒蛇钳{
私有静态缓冲阅读器pythonToJavaReader;
私有静态PrintWriter javaToPythonWriter;
公共PythonScriptExecuter()引发异常{
字符串MPBNScriptFile=“fullPathToScriptFile”;
ProcessBuilder pb=新的ProcessBuilder(“python”,MPBNScriptFile);
pb.重定向错误流(真);
//开始脚本
进程p=pb.start();
pythonToJavaReader=getOutputReader(p);//从python到java
javaToPythonWriter=getInputWriter(p);//从java到python
}
//Python=>Java
私有静态BufferedReader getOutputReader(进程p){
返回新的BufferedReader(新的InputStreamReader(p.getInputStream());
}
//Java=>Python
私有静态PrintWriter getInputWriter(进程p){
返回新的PrintWriter(新的OutputStreamWriter(p.getOutputStream());
}
公共静态Arraylist getResults(字符串参数)引发IOException{
//将参数发送到python脚本
println(参数);
//javaToPythonWriter.flush();
//一个接一个地把结果拿回来
ArrayList结果=新建ArrayList();
整数计数=0;
弦线;
而(!(line=pythonToJavaReader.readLine()).equals(“END”)){
//进程'line'字符串
结果:添加(行);
}
返回结果;
}
}
因此,我要做的是,在代码的初始化部分,我有一行简单的代码来启动这个过程:

新的MPBNPythonScriptExecuter();
稍后,当我想得到一些结果时,我会使用:

String arg = "something"
Arraylist<String> res = PythonScriptExecuter.getResults(arg);

您知道这里出了什么问题吗?

您可以使用管道在java和Python之间进行通信

您可以像现在一样运行Python(没有命令行参数)

Python脚本

用python编写一个无限循环,它将

  • 从数据库中读取数据 标准输入(它将是函数的参数)

  • 你调用你的函数

  • 将答案写入标准输出

  • 爪哇

  • 编写一个向python发送参数的方法

  • 将函数的参数写入管道

  • 从管道里读答案

  • 你完了

    这里有一些片段

    下面是如何创建管状体

            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()));
    }
    

    在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)
    

    您的Java代码应该或多或少是正确的。

    这听起来很有希望!我会在这个基础上制定一个解决方案,然后再回来找你!您还将避免.exec(),它将只执行一次,就像importt在这种情况下,脚本的此函数不能有并行请求,对吗?例如,两个进程同时调用函数(同一进程的
    p
    ),由于脚本写入
    stdout
    ,您不知道哪些结果将属于哪个。也许Java中的
    synchronized
    在这种情况下会有所帮助,will check.Hi Pascal!我遇到了一个问题,用我目前的方法编辑了这个问题。如果可能的话,你能检查一下吗?如果你需要一个并行调用,那么最好采用客户机/服务器的方法,但我认为这对于你的需要来说会非常复杂。使用IO管道的解决方案是一种顺序解决方案,您需要确保其安全并将同步添加到getResults方法中。您是否验证了python脚本没有错误?还需要用类似这样的东西捕获错误,而((ligne=error.readLine())!=null){System.out.println(“err:+ligne”);}不,更像是它在某种程度上没有正确读取(可能在正确的时间)。。。当我杀死java程序时,有时我可以在while循环中看到输出(我打印
    )-但只有在那时-就像它被卡住了一样…谢谢你的努力!这个问题仍然存在,我认为主要与Java部分有关。
    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)