IPC (межпроцессное взаимодействие) между python и java
Во-первых, небольшое объяснение, почему я задаю этот вопрос в первую очередь: я пишу программу на Python (с графическим интерфейсом wxPython), которая должна вызывать программу Java AWT из python и извлекать из нее данные. У меня есть рабочее решение для Windows. У меня также есть внутрипроцессное решение для OSX, пока я запускаю приложение Java без головы. К сожалению, нет разумного решения, которое я нашел для запуска обоих графических интерфейсов в одном и том же процессе в OSX, потому что и AWT, и WX оба хотят первый поток и не могут совместно использовать цикл сообщений wx.
То, что я хотел бы сделать, это запустить программу Java в отдельном процессе от моей программы Python и установить канал или очередь или что-то для передачи данных (в частности, байтовых массивов) назад и вперед.
Я был бы очень признателен за любые предложения или даже толчок в правильном направлении, так как у меня очень мало опыта работы с IPC.
7 ответов
Я пытался закодировать решение, используя каналы, но кажется, что они просто не подходят для отправки нескольких сообщений туда и обратно с прикрепленными потенциально большими данными. Скорее они кажутся идеальными для открытия программы в стиле "рабочий", которая запускается, отвечает и умирает.
Глядя на программирование сокетов, я нашел здесь фантастический ресурс: https://web.archive.org/web/20080913064702/http://www.prasannatech.net/2008/07/socket-programming-tutorial.html
В учебном пособии представлены TCP и UDP варианты простой программы чата, написанной на 4 языках. Я закончил тем, что использовал и изменил клиент TCP Java и сервер Python.
Это решение с открытым исходным кодом, которое Google использует для IPC между Java и Python. https://code.google.com/p/protobuf/
Рекомендуемые.
Именованные каналы могут быть ответом для вас. Смотрите: Создать временный FIFO (именованный канал) в Python?
IPC с использованием subprocess
из в питоне
Файл IPC.java здесь java-код получит номер и отправит его квадрат.
import java.util.Scanner;
public class IPC {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String data="";
while(scanner.hasNext()){
// Receive data from Python code
data = scanner.nextLine();
// Process data (calculate square)
int x = Integer.parseInt(data);
int square = x*x;
// Send data to python code
System.out.println(square);
}
scanner.close();
}
}
Файл IPC.py
import subprocess
subprocess.run(["javac", "IPC.java"])
proc = subprocess.Popen(["java", "IPC"], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
for i in range(10):
# Send to java code
proc.stdin.write(b'%d\n' % i)
proc.stdin.flush()
proc.stdout.flush()
# Receive data from java code
output = proc.stdout.readline()
print (output.rstrip())
proc.communicate()
Используйте subprocess.Popen, чтобы запустить процесс Java и установить каналы для связи с ним. Чтобы эффективно сериализовать и десериализовать данные не зависящим от языка, не зависящим от платформы, расширяемым способом, взгляните на буфер протоколов (предоставленный Jon Skeet!).
У меня была похожая ситуация, когда мне приходилось общаться между процессом Java и процессом Linux. Я использовал именованные каналы.
Попробуйте реализацию mkfifo() в python.
Межпроцессное взаимодействие между Python и Java
Реализация автономной, независимой от системы JRE в приложении Python.
Чтобы сделать приложение Python независимым от системы в целом, внутри приложения Python необходимо создать JRE. Это необходимо сделать, если требуется, чтобы приложение не зависело от системы и все было самодостаточно внутри приложения. Это полезно, если приложение в целом должно быть готово к запуску на любом компьютере пользователя без каких-либо дополнительных ресурсов и процедур при каждой установке.
Перейдите по адресу https://learn.microsoft.com/en-us/java/openjdk/download, загрузите JDK для желаемой аппаратной архитектуры и ОС и загрузите его в среду приложения Python. После этого поместите проект приложения Java целиком или.jar
файл, созданный из приложения Java в каталоге приложения Python.
Затем вы можете запустить приложение Java в приложении Python как подпроцесс.
Методы межпроцессного взаимодействия
Межпроцессное взаимодействие в реальном времени с использованием stdin , stout и stderr
,stdout
, иstderr
потоки — это основные системы ввода-вывода, которые ядро ОС использует для приложений и процессов. Изменяя поток этих потоков от дочернего процесса к ОС, от дочернего процесса к родительскому процессу, эти потоки будут пропускаться через родительский процесс, и родительский процесс будет иметь возможность выполнять операции ввода и вывода непосредственно с дочерним процессом.
[Код Java]
public class Main {
public static void main(String[] args)
{
// Send input over the "stdout" stream to the Python parent process
System.out.println("Message from Java application");
System.out.flush();
// Read input over the "stdin" stream from the Python parent process
Scanner s = new Scanner(System.in);
String input = s.nextLine();
s.close();
// Send input over the "stdout" stream to the Python parent process
System.out.println(input);
System.out.flush();
}
}
[Код Python]
import subprocess
# Path to java.exe, in case the application contains a self-contained java environment, else just the "java" command
path_to_java_exe = "C:\\Users\\Teodor Mihail\\PycharmProjects\\Python_IPC\\jre\\bin\\java.exe"
# Command line argument that specifies the compiler what it should compile, in this case is a ".jar" file
java_exe_arguments = "-jar"
# The path to the file that the compiler will run and the runtime will execute, in this case it is the whole program compiled as a ".jar" file
java_jar_file_path = "C:\\Users\\Teodor Mihail\\PycharmProjects\\Python_IPC\\Java_I.P.C.jar"
# Global variable that holds the sub-process
process = None
def subprocess_startup():
# Specify that the "process" variable is a reference to the global variable "process"
global process
# Open the process and redirect the "stdin", "stdout", and "stderr" streams from the sub-process to the OS to the Python process
process = subprocess.Popen([path_to_java_exe, java_exe_arguments, java_jar_file_path], stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
def subprocess_read_stdout():
# Read the output sent by the Java application sub-process over the "stdout" stream
received = process.stdout.readline()
print(received)
def subprocess_write_stdin(data):
# Write input to the Java application over the "stdin" stream
process.stdin.write(data.encode("utf-8"))
process.stdin.flush()
def main():
subprocess_startup()
# A loop can be implemented here for continuous read and write operations.
# Both the read and write operation methods can be open on different threads
# to perform continuous read and write operations executed in parallel
subprocess_read_stdout()
# Data to be written on the stdin stream must end in "\n" otherwise the Java
# Scanner will lock. This will happen because the Scanner in Java is
# scanning until a "\n" is found, otherwise it will wait indefinitely
# until it will find a "\n" within the input stream.
subprocess_write_stdin("Message from Python application\n")
subprocess_read_stdout()
if __name__ == '__main__':
main()
На каждомprocess.stdin.write
вызов метода, данные, отправленные дочернему процессу, должны завершаться символом новой строки ("\n
"). Это необходимо сделать, поскольку сканер Java будет сканироватьstdin
поток ищет символ новой строки, и поскольку поток буферизован, это приведет к блокировке потока, в котором выполняется эта операция.