ich zur Zeit versucht, die folgenden mit Py4J zu tun:Py4J Rückruf von Java Runnable
- Definieren Sie eine Methode ("Vollstrecker") in Python, die JVM Methoden aufruft
- eine Python definieren ("Rückruf") Objekt eine JVM Schnittstelle
- Konstruiere eine JVM Objekt gegeben dieses Rückrufobjekt
- Anruf Verfahren für dieses Objekt Implementierung, die den Rückruf auf dem Callback-Objekt einen neuen Thread in Java, nennen, laichen wird die wird (auf der Python Seiten) Ausführen der "Executor" -Methode
Hier ist, was ich auf der Java-Seite der Dinge haben:
package javabridge.test;
public interface PythonCallback {
Object notify(Object source);
}
package javabridge.test;
public class ScheduledRunnable implements Runnable {
private PythonCallback callback;
public ScheduledRunnable(PythonCallback callback) {
this.callback = callback;
}
@Override
public void run() {
System.out.println("[ScheduledRunnable] run -> notify");
this.callback.notify(this);
}
}
package javabridge.test;
import py4j.GatewayServer;
public class Test {
private PythonCallback callback;
public Test(PythonCallback callback) {
this.callback = callback;
}
public void runSynchronous() {
System.out.println("[runSynchronous] run -> notify");
this.callback.notify(this);
}
public void runAsynchronous() {
System.out.println("[runAsynchronous] run -> spawn thread");
ScheduledRunnable runnable = new ScheduledRunnable(callback);
Thread t = new Thread(runnable);
t.start();
}
public static void main(String[] args) {
GatewayServer server = new GatewayServer();
server.start(true);
}
}
Auf der Seite Python, ich habe das folgende Skript:
from py4j.java_gateway import JavaGateway, java_import, get_field, CallbackServerParameters
from py4j.clientserver import ClientServer, JavaParameters, PythonParameters
gateway = JavaGateway(callback_server_parameters=CallbackServerParameters())
#gateway = ClientServer(java_parameters=JavaParameters(), python_parameters=PythonParameters())
java_import(gateway.jvm, 'javabridge.test.*')
class PythonCallbackImpl(object):
def __init__(self, execfunc):
self.execfunc = execfunc
def notify(self, obj):
print('[PythonCallbackImpl] notified from Java')
self.execfunc()
return 'dummy return value'
class Java:
implements = ["javabridge.test.PythonCallback"]
def simple_fun():
print('[simple_fun] called')
gateway.jvm.System.out.println("[simple_fun] Hello from python!")
# Test 1: Without threading
input('Ready to begin test 1')
python_callback = PythonCallbackImpl(simple_fun)
nothread_executor = gateway.jvm.Test(python_callback)
nothread_executor.runSynchronous()
# Test 2: With threading
input('Ready to begin test 2')
python_callback = PythonCallbackImpl(simple_fun)
nothread_executor = gateway.jvm.Test(python_callback)
nothread_executor.runAsynchronous()
gateway.shutdown()
Folgendes passiert, wenn Sie versuchen, dieses Skript auszuführen. Zuerst mit gateway = ClientServer(java_parameters=JavaParameters(), python_parameters=PythonParameters())
, scheitern beiden Tests:
Test 1:
py4j.protocol.Py4JJavaError: An error occurred while calling o0.runSynchronous.
: py4j.Py4JException: Command Part is Empty or is the End of Command Part
at py4j.Protocol.getObject(Protocol.java:277)
at py4j.Protocol.getReturnValue(Protocol.java:458)
Test 2:
Exception in thread "Thread-4" py4j.Py4JException: Error while obtaining a new communication channel
at py4j.CallbackClient.getConnectionLock(CallbackClient.java:218)
at py4j.CallbackClient.sendCommand(CallbackClient.java:337)
at py4j.CallbackClient.sendCommand(CallbackClient.java:316)
Allerdings, wenn ich die self.execfunc()
Zeilen aus kommentieren, Test 1 funktioniert ohne Fehler zu erhöhen. jedoch Test 2 immer noch nicht:
Exception in thread "Thread-5" py4j.Py4JException: Error while sending a command.
at py4j.CallbackClient.sendCommand(CallbackClient.java:357)
at py4j.CallbackClient.sendCommand(CallbackClient.java:316)
Jetzt gateway = JavaGateway(callback_server_parameters=CallbackServerParameters())
wechseln. Als ich self.execfunc()
halten Kommentar gesetzt, Test 2 immer noch nicht hier:
Exception in thread "Thread-5" py4j.Py4JException: Error while sending a command.
at py4j.CallbackClient.sendCommand(CallbackClient.java:357)
at py4j.CallbackClient.sendCommand(CallbackClient.java:316)
Aber zumindest Test 1 funktioniert mit self.execfunc()
aktiviert.
Meine Frage ist: Wie kann ich den Gewindeansatz mit dem self.execfunc()
Aufruf verwenden? Ist das mit Py4J möglich?
Edit: und um die Dinge noch komplizierter zu machen, sollten Java-Befehle, die von self.execfunc()
aufgerufen werden, im selben Java-Thread ausgeführt werden, der .notify()
aufgerufen hat.