Inline::Java与Parallel::ForkManager冲突

3

我在同时调用Parallel::ForkManagerInline::Java时遇到了问题。具体来说,如果我使用JNI => 1选项调用Inline::Java(我必须这样做),那么fork进程就不会返回到父进程。以下是代码:

use Parallel::ForkManager;

##### Calling Inline::Java #####
use Inline Java => <<END, JNI => 1;

END
###### End of Inline::Java #####

my $pm = Parallel::ForkManager->new(2);
for my $i (0..1) {
    $pm->start and next;
    print "Inside process $i\n";
    $pm->finish;
}
$pm->wait_all_children;
print "Back to Parent.\n";

如果我运行这个程序,它会进入子进程但永远不会回到父进程。如果我删除注释之间的3行代码,它就能正常运行。如果我将JNI => 1更改为JNI => 0(虽然我不允许为我的目的更改该参数),那么就会出现错误消息:Lost connection with Java virtual machine at /usr/lib64/perl5/site_perl/5.8.8/x86_64-linux-thread-multi/Inline/Java.pm line 975
有人知道如何解决这个冲突吗?我还必须在并行处理之前调用Inline::Java,因此在并行处理完成后使用require不是一个选项。谢谢!
2个回答

2
每个孩子都在同一个套接字上交流,这会导致虚拟机收到无意义的信息。您需要延迟与虚拟机建立连接,使其在子进程中完成而不是在父进程中完成。 您可以将所有与Inline::Java相关的内容移动到另一个模块中,然后在start之后使用require Child;(而不是use Child;)。 如果需要在启动子进程之前使用Inline::Java,请在不同的进程中执行它。

感谢你的分析。不过很遗憾,你提供的解决方案对我来说并不适用,因为正如我在原问题的结尾所指出的那样,Inline::Java进程必须在分叉之前执行。顺便说一下,Inline::Java已经在一个单独的模块中了,我只是把所有的脚本合并在这里以说明问题。 - Zhang18
@Zhang18,请再仔细阅读。我的解决方案并不会阻止您在P::FM循环之前使用Inline::Java。您只需要在单独的进程中执行即可。 - ikegami
我明白了 - 你说得对。我成功地做到了不需要进入每个子进程来调用JVM,而是只需进入一个子进程,调用JVM,将结果返回给父进程,然后再分叉成多个子进程。所以关键是永远不要在父进程中运行JVM。非常感谢! - Zhang18

2
“使用Inline::Java的分叉将会是一个问题。你的Perl脚本需要与JVM保持TCP连接。当你fork一个新进程时,用于与JVM通信的相同文件描述符将被传递给子进程,因此父进程和所有子进程都使用相同的套接字。这不起作用。你需要重新设计你的应用程序。”
“一种可能性(你已经排除了)是在分叉后延迟启动JVM,在每个子进程中启动一个新的JVM。”
“另一种方法是忘记从Perl进行分叉,利用Java的优越线程模型进行并行化。设计你的Java代码以在新线程中执行其任务,并从Perl启动新线程:”
my $java = ... entry point to JVM ...

for my $n (1 .. $num_threads) {
    $java->startNewThread(@inputs)
}
$java->waitForThreadsToFinish();
$result = $java->getResults();

Perl也有自己的线程模型(请参阅threadsthreads::shared)。我怀疑Perl的线程对于这个问题可能行不通,但还是值得一试的。
更新:Inline::Java 文档中提到的另一个可能性是使用共享 JVM。使用选项 SHARED_JVM => 1 调用 Inline::Java,当一个新的子进程启动时,从子进程中调用 Inline::Java::reconnect_JVM() 来建立一个新连接。这种方法的缺点是:
  1. 程序结束后仍保持 JVM 活动状态,因此必须记得杀死 JVM。
  2. 它与选项 JNI => 1 不兼容,这可能会成为问题的关键点。

Perl的线程无法解决问题,因为您仍然会遇到多个任务尝试同时使用同一个套接字的问题。 - ikegami
只是为了明确,Java线程方法应该可以工作。我仅就mob最后一段的评论发表意见。 - ikegami

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接