#perl #parallel-processing #inline
#perl #параллельная обработка #встроенный
Вопрос:
У меня возникли проблемы с одновременным вызовом обоих Parallel::ForkManager
и Inline::Java
одновременно. В частности, если я вызываю Inline::Java
с JNI => 1
опцией (которая у меня есть), то процесс 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 $in";
$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
после завершения параллели не является вариантом. Спасибо!
Ответ №1:
Каждый дочерний элемент разговаривает через один и тот же сокет, что приводит к тому, что виртуальная машина получает болтовню.
Вам нужно отложить подключение к виртуальной машине, чтобы это было сделано в дочерних системах, а не в родительской.
Вы могли бы переместить все, что связано с Inline ::Java, в другой модуль, а затем использовать require Child;
(не use Child;
) после start
.
Если вам нужно использовать Inline::Java перед запуском дочернего элемента, сделайте это в другом процессе.
Комментарии:
1. Ценю ваш анализ. Однако ваше решение, к сожалению, не подходит для меня для реализации, поскольку я отметил в конце исходного вопроса, что процесс Inline:: Java должен выполняться до разветвления. кстати, Inline::Java уже находится в отдельном модуле. Я просто объединил все скрипты здесь для иллюстрации.
2. @Zhang18, прочитай еще раз. Мое решение не мешает вам использовать Inline::Java перед циклом P::FM. Вам просто нужно сделать это в отдельном процессе.
3. Я вижу — вы абсолютно правы. Вместо того, чтобы обращаться к каждому дочернему процессу для вызова JVM, мне удалось просто перейти к одному дочернему процессу, вызвать JVM, вернуть результаты родительскому, а затем разветвить на множество дочерних процессов. Итак, ключ в том, чтобы никогда не запускать JVM в родительском. Спасибо большое!
Ответ №2:
Использование forks с Inline::Java
будет проблемой. Ваш сценарий perl должен поддерживать TCP-соединение с JVM. Когда вы разветвляете новый процесс, дочернему процессу передаются те же файловые дескрипторы для связи с JVM, поэтому родительский и все дочерние процессы используют одни и те же сокеты. Это не сработает. Вам необходимо перепроектировать свое приложение.
Одна из возможностей (которую вы уже исключили) заключается в том, чтобы отложить запуск JVM до завершения fork, запустив новую 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 также имеет свою собственную модель потоков (см. threads
и threads::shared
). Я сомневаюсь, что потоки Perl будут работать для решения этой проблемы, но, возможно, стоит попробовать.
Обновление: другая возможность, которая упоминается в Inline::Java
документах, заключается в использовании общей виртуальной машины. Вызывайте Inline::Java
с опцией SHARED_JVM => 1
, и когда запускается новый дочерний процесс, вызывайте Inline::Java::reconnect_JVM()
из дочернего процесса, чтобы установить новое соединение. Недостатками этого подхода являются
- это сохраняет JVM активной после завершения программы, поэтому вы должны помнить, что нужно отключить JVM
- это несовместимо с опцией
JNI => 1
, которая может привести к нарушению работы операционной системы.
Комментарии:
1. Потоки Perl не помогут, потому что у вас все равно будет та же проблема с несколькими задачами, пытающимися одновременно использовать один и тот же сокет.
2. Просто для ясности, подход Java thread должен работать. Мой комментарий касается только замечаний в последнем абзаце mob.