Py4j launch_gateway不正确连接
我试图用py4j开拓,我可以用它来从Java对象进入蟒蛇的网关。当我尝试使用py4j函数launch_gateway
打开网关时,它似乎无法正确连接到我的Java类。但是,当我在命令行中启动我的java类,然后使用JavaGateway
在python中连接它时,所有内容都按预期工作。我希望能够使用内置方法,因为我确信我没有考虑py4j设计中已经考虑过的事情,但我只是不确定我做错了什么。Py4j launch_gateway不正确连接
比方说,我想创建一个门户类sandbox.demo.solver.UtilityReporterEntryPoint.class
。在命令行中,我可以通过执行以下操作如下:
java -cp /Users/grr/anaconda/share/py4j/py4j0.10.4.jar: sandbox.demo.solver.UtilityReporterEntryPoint py4j.GatewayServer
如预期,我可以连接到网关后,蟒蛇内使用的方法在我的课从这个启动。到现在为止还挺好。
我的py4j文件的理解将导致我相信我应该做到以下几点启动网关蟒蛇:
port = launch_gateway(classpath='sandbox.demo.solver.UtilityReporterEntryPoint')
params = GatewayParameters(port=port)
gateway= JavaGateway(gateway_parameters=params)
我执行这三条线时没有错误,但是当我尝试访问我与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
的py4j源代码中,您可以看到,如果给定了您提供的输入以及由函数构造的输入,则会构造一条命令,最终将由subprocess.Popen
调用该命令。因此,给予传递给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.GatewayServer.class的Java源代码后,这是没有意义的,因为主要方法似乎表明如果参数长度为0,类应该以状态1退出。
在这一点上,我有点不知所措。我可以用自己的方式进入一个可行的解决方案,但正如我所说的,我肯定忽略了网关行为的重要方面,我不喜欢哈克解决方案。我很想在这个标签中添加@Barthelemy,但希望他读到这个。预先感谢您的帮助。
编辑
现在我已经能够解决这个问题,下面的步骤。
包装整个项目在内的所有外部依赖到一个JAR文件
magABM-all.jar
,与“主类”设置为UtilityReporterEntryPoint
。包括
if...else
关于--die-on-exit
存在块酷似它在GatewayServer.java
使用
subprocess.Popen
调用命令运行项目罐子。
UtilityReporterEntryPoint.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);
}
}
}
app.py
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
,如果蟒蛇进程死亡或者是关闭的网关将被关闭。
NB我绝不认为这是一个最终的解决方案py4j被写了更聪明的人在考虑一个明确的目的,我相信,有管理py4j的范围内这一确切工作流的方式。这只是一个权宜之计。
有几个问题:
在
launch_gateway
类路径参数应是一个目录或jar文件,而不是一个类名。例如,如果要包含其他Java库,则可以将它们添加到classpath参数中。当您拨打
gateway.entry_point.someMethod()
时收到的错误表示您没有入口点。当您调用launch_gateway
时,JVM将启动GatewayServer.main,该启动不带入口点的GatewayServer: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作为主类。虽然您没有提供代码,但我认为此类具有主要方法,并且它以UtilityReporterEntryPoint实例作为入口点启动GatewayServer。请注意冒号和类名之间有一个空格,所以UtilityReporterEntryPoint被视为主类,而不是作为类路径的一部分。
感谢您的回复。我想我对第2点有点困惑。你是否用'launch_gateway'说我没有办法启动我的类'UtilityReporterEntryPoint'?如果有,我是否有办法在启动后设置入口点? – Grr
我仍然想更多地了解如何正确使用'launch_gateway'方法,但现在我想出了一些解决方法。看看我更新的问题,并让我知道这是否合理。就像我说过的,我真的很想知道如何以正确的方式做到这一点,而不仅仅是一些冒险的修复。 – Grr
@Grr无法使用launch_gateway指定主类,因此无法指定入口点。 launch_gateway的目标是尽快开始。只要你需要更多的配置选项,最好推出自己的策略,比如你创建的app.setup_gateway函数。您也可以考虑打开一个功能请求来支持自定义Main类,但正如您在--die-on-exit时看到的那样,Main类仍然需要遵循某些协议。 – Barthelemy