首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Py4j launch_gateway未正确连接

Py4j launch_gateway未正确连接
EN

Stack Overflow用户
提问于 2017-04-07 15:56:01
回答 1查看 2.1K关注 0票数 0

我试图使用py4j打开一个网关,可以用来将对象从java传递到python。当我尝试用py4j函数launch_gateway打开网关时,它似乎没有正确地连接到我的launch_gateway类。但是,当我在命令行中启动我的java类,然后使用JavaGateway在python中连接到它时,一切都如期而至。我希望能够使用内置方法,因为我确信我没有考虑到在py4j设计中已经考虑过的事情,但我只是不知道我做错了什么。

假设我想创建一个通往类sandbox.demo.solver.UtilityReporterEntryPoint.class的网关。在命令行中,我可以通过执行以下命令来做到这一点:

代码语言:javascript
复制
java -cp /Users/grr/anaconda/share/py4j/py4j0.10.4.jar: sandbox.demo.solver.UtilityReporterEntryPoint py4j.GatewayServer

这将按预期启动,在连接到网关后,我可以在python中使用类中的方法。到目前一切尚好。

我对py4j文档的理解将使我相信我应该做以下工作来启动python中的网关:

代码语言:javascript
复制
port = launch_gateway(classpath='sandbox.demo.solver.UtilityReporterEntryPoint')
params = GatewayParameters(port=port)
gateway= JavaGateway(gateway_parameters=params)

执行这三行时没有错误,但是当我尝试使用gateway.entry_point.someMethod()访问java类方法时,它会失败,原因如下:

Py4JError:调用t.getReport时出错。跟踪: py4j.commands.AbstractCommand.invokeMethod(AbstractCommand.java:132):py4j.commands.CallCommand.execute(CallCommand.java:79) at py4j.GatewayConnection.run(GatewayConnection.java:214) at java.lang.Thread.run(Thread.java:745),此网关不存在目标对象ID :t at py4j.Gateway.invoke(Gateway.java:277)

很明显,在launch_gateway中有些东西没有被正确的调用,或者我给它提供了错误的信息。

在py4j的launch_gateway源代码中,您可以看到,给定您提供的输入和由函数构造的输入,将构造一个命令,最终由subprocess.Popen调用。因此,考虑到上面传递给launch_gateway的输入,传递给Popen的命令是:

代码语言:javascript
复制
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源代码之后,这是没有意义的,因为主方法似乎表明,如果参数长度为0,类应该退出状态1。

现在我有点不知所措。我可以黑进一个可行的解决方案,但正如我所说,我确信忽略网关行为的重要方面,我不喜欢黑客解决方案。我很想在这篇文章中加上@Barthelemy的标签,但希望他能读到这个。提前感谢您的帮助。

编辑

目前,我已经能够通过以下步骤来解决这个问题。

  1. 将包含所有外部依赖项的整个项目打包到一个jar文件magABM-all.jar中,并将“Main”设置为UtilityReporterEntryPoint
  2. 包括关于--die-on-exit存在的--die-on-exit块,与GatewayServer.java中的情况完全一样
  3. 使用subprocess.Popen调用命令来运行项目jar。

UtilityReporterEntryPoint.java

代码语言:javascript
复制
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

代码语言:javascript
复制
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的范围内管理这个精确的工作流。这只是一个权宜之计。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-04-08 00:27:27

有几个问题:

  1. launch_gateway中的类路径参数应该是目录或jar文件,而不是类名。例如,如果希望包含其他Java库,可以将它们添加到类路径参数中。
  2. 当您调用gateway.entry_point.someMethod()时收到的错误意味着您没有入口点。当您调用launch_gateway时,JVM是用GatewayServer.main启动的,它启动一个没有入口点的GatewayServer:GatewayServer server = new GatewayServer(null, port)。目前不可能使用launch_gateway并指定入口点。
  3. 当您使用java -cp /Users/grr/anaconda/share/py4j/py4j0.10.4.jar: sandbox.demo.solver.UtilityReporterEntryPoint py4j.GatewayServer启动JVM时,我相信JVM使用UtilityReporterEntryPoint作为主类。虽然您没有提供代码,但我假设这个类有一个main方法,并且它以GatewayServer实例UtilityReporterEntryPoint作为入口点来启动它。注意,冒号和类名之间有一个空格,因此UtilityReporterEntryPoint被看作是主类,而不是类路径的一部分。
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43282447

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档