Py4j启动网关连接不正确

2024-09-27 07:29:01 发布

您现在位置:Python中文网/ 问答频道 /正文

我尝试使用py4j打开一个网关,可以用来将对象从java传递到python。当我试图用py4j函数^{}打开网关时,它似乎无法正确连接到我的Java类。但是,当我在命令行中启动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中没有正确调用某些内容,或者我给它输入了错误的信息。在

^{}的py4j源代码中,您可以看到给定您提供的输入和函数构造的输入,一个命令最终由^{}调用。因此,给定传递给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,但希望他能读到这篇文章。提前谢谢你的帮助。在

编辑

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

  1. 将包含所有外部依赖项的整个项目打包到单个jar文件magABM-all.jar,并将“Main Class”设置为UtilityReporterEntryPoint

  2. 包括if...else块,关于--die-on-exit的存在,就像它在^{}中一样

  3. 使用^{}调用命令来运行项目jar。

乌提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的范围内管理这个精确的工作流。这只是一个权宜之计。在


Tags: 方法命令网关newexitjavasystemgateway
1条回答
网友
1楼 · 发布于 2024-09-27 07:29:01

有几个问题:

  1. launch_gateway中的classpath参数应该是目录或jar文件,而不是类名。例如,如果要包含其他Java库,可以将它们添加到classpath参数中。

  2. 调用gateway.entry_point.someMethod()时收到的错误表示您没有入口点。当您调用launch_gateway时,JVM以网关服务器.main,它启动一个没有入口点的网关服务器: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,其中一个utilityReporteryPoint实例作为入口点。注意,冒号和类名之间有一个空格,因此UtilityReporterEntryPoint被视为主类,而不是类路径的一部分。

相关问题 更多 >

    热门问题