簡體   English   中英

通過 Java 運行 Python 腳本,只需導入一次

[英]Run Python script through Java with importing just once

2020 年 4 月更新:我接受了下面的答案,因為它為我的問題提出了一個非常好的和簡單的解決方案,但我的代碼從來沒有工作過! 如果有人已經建立了類似的東西,請聯系我!


我有一個簡單的腳本my-script.py使用Python編寫的特定庫非常快速地進行一些計算:

import sys
import special-library

def fun(x):
  do something

fun(sys.argv[1])

在我的Java代碼中,我在代碼的不同部分使用/調用此腳本很多,使用ProcessBuilder方法,這意味着我只需運行命令python my-script.py argument 這意味着每次我調用這個腳本時,我都必須執行import命令,這是其中最耗時的事情(計算部分實際上更快)。

有沒有辦法讓我只調用一次導入 我看了一點關於Jython的信息 - 是否可以編寫 class 或一些可以啟動並執行一次導入然后每次我想做計算部分時調用它的 function 的東西( fun )? 有沒有人做過類似的事情或有任何其他解決方案?

首次嘗試實施

我試圖編寫一個“管道” Java Class 將執行 python 腳本一次。 現在腳本從標准輸入連續讀取,當它獲得輸入argument時,它會進行計算並返回結果:

import sys
import special-library

def fun(x):
  do something
  print('END')

for arg in sys.stdin:
  fun(arg)

當我從命令行對其進行測試並為其提供輸入 arguments 時,這當然有效。

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

所以,我所做的是在我的代碼的初始化部分的某個地方,我有這個簡單的行來啟動這個過程:

new MPBNPythonScriptExecuter();

后來當我想得到一些結果時,我使用:

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

整個事情都掛在從腳本讀取輸出的行上:

while (!(line = pythonToJavaReader.readLine()).equals("END"))

任何想法這里出了什么問題?

您可以使用管道在 java 和 Python 之間進行通信。

您像現在一樣運行 Python(沒有命令行參數)

Python 腳本

您在 python 中編寫了一個無限循環,它將

  1. 從標准輸入讀取數據(這將是函數的參數)

  2. 你打電話給你的 function

  3. 你寫下標准 output 的答案

Java

  1. 編寫發送args到python的方法

  2. 將 function 的 arg 寫入 pipe

  3. 從 pipe 中閱讀答案

你完成了。

這是一些片段

在這里你如何創建你的管

        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 代碼應該或多或少是正確的。

我做了一個類似的項目。 我們的選擇是 Jython、Jep、graalVM 和套接字技術。 事實上,我從未測試過 Jython,因為我需要調用 numpy,這是不可能的。 Jep 看起來很有希望,但你必須為特定版本構建它,我無法讓它工作。 GraalVM 非常好,但是它當時並不存在並且(它不適用於 windows,但不用擔心你可以制作二進制文件)並且它仍然是實驗性功能。 所以唯一的選擇是 sockets 技術。 您可以輕松地在 java 中制作插座,同樣在 python 中制作插座。 然后編寫一組 function 將字符串轉換為原始 arrays ,反之亦然。 缺點是需要針對您的機器 python 和通信時間進行編譯。 我把項目放在git上,希望對你有用。
項目的回購: https://github.com/amirshamaei/HLSVDPro4J

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM