Сервер Rserve: как завершить блокирующий экземпляр (eval навсегда)?

Мне нужно выполнять R evals многопоточным способом, что Rserve обеспечивает довольно хорошо. Но если оценка одного экземпляра занимает слишком много времени, мне нужно иметь возможность отключить экземпляр, который вычисляет оценку блокировки. Насколько я проверял, данный экземпляр отказывается выключаться до тех пор, пока не будет выполнена оценка (очевидно, ему нужно получить результат, прежде чем снова слушать). Вот мой вопрос:

Есть ли способ получить дескриптор java для экземпляра блокировки (что-то вроде объекта Process), чтобы я мог убить/прекратить eval грубой силой (что-то вроде process.destroy())? Другими словами, когда я запрашиваю eval (создаю соединение, бросаю команду), как мне установить связь между обрабатываемым eval и связанным с ним экземпляром Rsere через java?

Или я что-то пропустил в Rserve, который уже позволяет справляться с такого рода потребностями?

Примечание: я уже пробовал запускать все (все evals) через serverEval() вместо обычного eval, который запускает вычисления на основном экземпляре, но это, конечно, неудовлетворительно, так как используется только один процесс (основной). Этого я могу убить, но моя главная цель состояла в том, чтобы иметь возможность индивидуально отключить блокирующий eval, работающий на отдельном экземпляре. И, естественно, сохранить преимущества моих 8 ядер процессора, то есть сохранить параллелизм. В противном случае нет смысла использовать Rserve (в этом случае движка JRI будет более чем достаточно).

Примечание. Я хотел бы избежать подобных вещей (thread), работающий с несколькими экземплярами самого главного сервера на разных портах. Это не вариант.

Я уже пытался получить информацию в списке рассылки Rserve, но не получил ответа. Надеюсь, я достаточно ясно выразился, чтобы получить здесь ответ или полезный комментарий. Если нет, пожалуйста, запросите подробности. Большое спасибо заранее.

Изменить: я также протестировал RCaller, который экземпляры R нужны, но, поскольку он записывает результаты в файлы XML для последующего анализа со стороны java (на самом деле не используя протокол связи, как Rserve), он слишком медленный для того, что я должен выполнить...


person Gauthier Boaglio    schedule 21.11.2014    source источник


Ответы (2)


Хорошо, это можно сделать следующим образом (поймал это от какого-то приятного человека, который, наконец, ответил мне в списке рассылки Rserve devel):

В потоке, выполняющем eval, предполагается, что он блокируется или слишком длинный, и предполагается, что Rserve запущен:

private RConnection rEngine = null;
private int rServePid = -1;

//...

// Keep an opened instance and store the related pid
RConnection rconn = new RConnection();
this.rServePid = rconn.eval("Sys.getpid()").asInteger();
this.rEngine = rconn;
LOG.info("Rserve: started instance with pid '" + this.rServePid + "'.");
//...
this.rEngine.eval("some consuming code...");

Что позволяет отслеживать pid экземпляра, связанного с указанным eval (R privides Sys.getpid()).

Затем, чтобы остановить/прервать/отменить и, поскольку простой this.rEngine.close() не остановит задачу, обрабатываемую на стороне сервера, а только закроет соединение, нам нужно убить целевой экземпляр Rserve. Это можно сделать, вызвав tools::pskill() (или любой другой системный вызов, например, kill -9 my_pid (UNIX*), TASKKILL /PID my_pid /F (Windows), ..., в зависимости от платформы), очевидно, из другого потока, чем тот, что указан выше (который ожидает "eval часть", чтобы вернуться):

// Terminate.
RConnection c2 = new RConnection();
// SIGTERM might not be understood everywhere: so using SIGKILL signal, as well.
c2.eval("tools::pskill("+ this.rServePid + ")");
c2.eval("tools::pskill("+ this.rServePid + ", tools::SIGKILL)");
c2.close();
LOG.info("Rserve: terminated instance with pid '" + this.rServePid + "'.");

Преимущество этого заключается в том, что он не зависит от платформы.

Надеюсь, это может помочь.

person Gauthier Boaglio    schedule 26.11.2014
comment
Это работает. Но если я попробую что-то вроде rEngine = new RConnection(); //get the pid of rEngine and do the time consuming eval using rEngine.. //Terminate RConnection c2 = new RConnection(); // SIGTERM might not be understood everywhere: so using SIGKILL signal, as well. c2.eval("tools::pskill("+ this.rServePid + ")"); c2.eval("tools::pskill("+ this.rServePid + ", tools::SIGKILL)"); c2.close(); , процесс будет убит, но использование процессора Rserve возрастет, и Rserver не разрешает никаких новых подключений. У вас есть идеи, почему? - person raiyan; 01.12.2015
comment
Похоже, что последний eval не возвращается и продолжает занимать все ядро. В некоторых случаях вам придется получить все дерево процессов (необходимо убить родительский процесс, чтобы действительно отключить его). Конечно, этот подход зависит от платформы. Вместо этого у меня есть пакетные сценарии Windows / OSX и NUX (вызывается системой). Дайте мне знать, если вам нужен более конкретный материал. Ваше здоровье. - person Gauthier Boaglio; 02.12.2015
comment
я не хочу убивать все дерево процессов. Кто-то другой будет работать над тем же Rserve, и уничтожение всего процесса также уничтожит его экземпляр. Однако проблема не в eval. Eval возвращается, и выполнение кода переходит к следующей строке. Но загрузка процессора достигает пика при убийстве экземпляра. - person raiyan; 02.12.2015
comment
Да я вижу. Таким образом, это держит компьютер занятым на некоторое время. Все заморожено или попытки новых подключений в какой-то момент увенчались успехом? Честно говоря, я не вижу причин для этого, если вы не адресуете свое «убийственное соединение» к уже занятому серверу Rserve. Примечание. Rserve не может создавать дочерние соединения в Windows, как это было бы в *NUX. Поэтому, если вы работаете под Windows, вам, возможно, придется иметь дело с несколькими экземплярами Rserve. Посмотрите, например, как обрабатываются вещи в этой оболочке Rserve (которую я бы использовал, если бы я указал вам: Rsession. - person Gauthier Boaglio; 02.12.2015
comment
Посмотрите, как нерестовые экземпляры должны быть emulated под окнами. Какая у вас ОС, кстати? - person Gauthier Boaglio; 02.12.2015
comment
Новые подключения не принимаются в любой момент после команды kill, пока не будет перезапущен процесс rserve. Rserve работает на Linux-машине, а соединения выполняются с Windows-машины. Java-оболочка действительно хороша, но у меня есть своя собственная оболочка. Я просто хочу знать, почему Rserve зависает, когда команда pskill отправляется из другого экземпляра Rserve. Этого не произойдет, если я использую ту же команду из локального сеанса R на сервере, на котором работает Rserve. - person raiyan; 04.12.2015
comment
Хорошо, извините, я не могу помочь. Мой опыт работы с Rserve ограничен локальным использованием (моя цель при его использовании состоит только в том, чтобы иметь возможность запускать несколько задач R параллельно, чего невозможно достичь с помощью таких интерфейсов, как JRI,...). Кажется, вы определили, что проблема связана с сетевым протоколом. Я предлагаю вам задать вопрос в списке рассылки Rserve devel ( эти люди дали мне ответы, когда я не мог получить их в другом месте). Спасибо, что поделились здесь, если вы, наконец, выясните, в чем была проблема и как ее исправить. Ваше здоровье. - person Gauthier Boaglio; 07.12.2015

Как насчет

rcon.eval("system(\"echo $$\", intern = TRUE)");

Он вернет pid запущенного Rserve (не основного), а затем вы можете убить его, используя этот pid.

person Peerapan Laorchairangsi    schedule 19.04.2016