我尝试使用py4j打开一个网关,可以用来将对象从java传递到python。当我试图用py4j函数^{
假设我想创建一个到类sandbox.demo.solver.UtilityReporterEntryPoint.class
的网关。在命令行中,我可以执行以下命令:
java -cp /Users/grr/anaconda/share/py4j/py4j0.10.4.jar: sandbox.demo.solver.UtilityReporterEntryPoint py4j.GatewayServer
这将按预期启动,在连接到网关之后,我可以从python内部使用类中的方法。到现在为止,一直都还不错。在
我对py4j文档的理解会使我相信应该执行以下操作以用python启动网关:
^{pr2}$我在执行这三行时没有出错,但是当我试图用gateway.entry_point.someMethod()
访问我的java类方法时,它失败了,并出现以下错误:
Py4JError: An error occurred while calling t.getReport. Trace: py4j.Py4JException: Target Object ID does not exist for this gateway :t at py4j.Gateway.invoke(Gateway.java:277) at py4j.commands.AbstractCommand.invokeMethod(AbstractCommand.java:132) at py4j.commands.CallCommand.execute(CallCommand.java:79) at py4j.GatewayConnection.run(GatewayConnection.java:214) at java.lang.Thread.run(Thread.java:745)
显然在launch_gateway
中没有正确调用某些内容,或者我给它输入了错误的信息。在
在^{launch_gateway
的输入,传递到Popen
的命令将是:
command = ['java', '-classpath', '/Users/grr/anaconda/share/py4j/py4j0.10.4.jar:sandbox.demo.solver.UtilityReporterEntryPoint', 'py4j.GatewayServer', '0']
将此命令传递给Popen
将按预期返回侦听端口。但是,连接到这个侦听端口仍然不允许访问我的类方法。在
最后,将命令作为一个字符串传递给Popen而不带最后一个参数(“0”),将正确启动网关,该网关将再次按预期运行。浏览了一下py4j的Java源代码。网关服务器.class这没有意义,因为main方法似乎指示如果参数长度为0,则类应该以状态1退出。在
现在我有点不知所措。我可以用我的方法找到一个可行的解决方案,但正如我所说,我确信这忽略了网关行为的重要方面,我不喜欢黑客解决方案。我很想在这本书里加上@Barthelemy,但希望他能读到这篇文章。提前谢谢你的帮助。在
编辑
目前,我已经能够通过以下步骤解决这个问题。在
将包含所有外部依赖项的整个项目打包到单个jar文件magABM-all.jar
,并将“Main Class”设置为UtilityReporterEntryPoint
。
包括if...else
块,关于--die-on-exit
的存在,就像它在^{
使用^{
乌提tyReporterEntryPoint.java在
public static void main(String[] args) throws IOException {
GatewayServer server = new GatewayServer(new UtilityReporterEntryPoint());
System.out.println("Gateway Server Started");
server.start();
if (args[0].equals("--die-on-exit")) {
try {
BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in, Charset.forName("UTF-8")));
stdin.readLine();
System.exit(0);
} catch (java.io.IOException e) {
System.exit(1);
}
}
}
在应用程序副本在
def setup_gateway()
"""Launch a py4j gateway using UtilityReporterEntryPoint."""
process = subprocess.Popen('java -jar magABM-all.jar --die-on-exit', shell=True)
time.sleep(0.5)
gateway = JavaGateway()
return gateway
通过这种方式,我仍然可以在必要时使用gateway.shutdown
,如果启动py4j网关的python进程死亡或关闭,则网关将被关闭。在
N.B我绝不认为这是一个最终的解决方案,因为py4j是由更聪明的人编写的,有明确的目的,我确信有一种方法可以在py4j的范围内管理这个精确的工作流。这只是一个权宜之计。在
有几个问题:
launch_gateway
中的classpath参数应该是目录或jar文件,而不是类名。例如,如果要包含其他Java库,可以将它们添加到classpath参数中。调用
gateway.entry_point.someMethod()
时收到的错误表示您没有入口点。当您调用launch_gateway
时,JVM以网关服务器.main,它启动一个没有入口点的网关服务器:GatewayServer server = new GatewayServer(null, port)
。当前无法使用launch_gateway
并指定入口点。当您使用
java -cp /Users/grr/anaconda/share/py4j/py4j0.10.4.jar: sandbox.demo.solver.UtilityReporterEntryPoint py4j.GatewayServer
启动JVM时,我相信JVM使用UtilityReporterEntryPoint作为主类。虽然您没有提供代码,但是我假设这个类有一个main方法,并且它启动了一个GatewayServer,其中一个utilityReporteryPoint实例作为入口点。注意,冒号和类名之间有一个空格,因此UtilityReporterEntryPoint被视为主类,而不是类路径的一部分。相关问题 更多 >
编程相关推荐