Блокировка и ожидание в R

мне было бы очень полезно создать функцию в R, которая могла бы блокировать, пока ресурс не будет определен или не будет задано соответствующее значение. Я знаю, что R однопоточен, но я надеялся, что mc сможет помочь. Однако,

library(parallel)
f = function() {
  while(!exists('a')) Sys.sleep(1);
  print('success!')
}
d = mcparallel(f())
a = 1
mccollect(d)

зависает на неопределенный срок. Есть ли какой-либо эффективный обходной путь, или мне придется искать радикально разные шаблоны/другой язык, чтобы достичь чего-то подобного?

3 ответов


Я даже не знал, что можно развить такие процессы. Поиграв немного, я нашел sendChildStdin функция, которую вы должны проверить. Это как минимум один способ сигнала дочерние процессы. Вот пример:

f<- function () {
  message<-scan(n = 1, quiet = TRUE, what='character')
  return(message)
}
p  <- mcparallel(f())
a <- 1
# The message shouldn't contain spaces and should end with a newline.
parallel:::sendChildStdin(p, "created\n") 
mccollect(p)[[1]]
[1] "created"

Не поймите меня неправильно; R, вероятно, не тот язык, который вы хотите, если вы собираетесь попасть в материал сильно, но он может работать для легких приложений.


Я тестировал код раньше в RStudio, и хотя он казалось, что это работает, он терпел неудачу таким образом, который был неотличим от успеха. Во всяком случае, он по существу не ждет scan процесс. Например, это никогда не должно завершаться, но это (только в RStudio)

f<- function () {
  message<-scan(n = 1, quiet = TRUE, what='character')
  return(message)
}
p  <- mcparallel(f())
# parallel:::sendChildStdin(p, "created\n")
mccollect(p)[[1]]
# character(0)

другой хак, с небольшим, чтобы рекомендовать его, чтобы адаптировать пример в нижней части ?socketConnection общение между двумя процессами с помощью сокетов. Мы делаем раздвоенный процесс сервером (сервер должен быть запущен первым, поэтому не может быть интерактивным процессом) и отправляем его по пути...

f <- function() {
    system.time({
        con1 <- socketConnection(port = 6011, server = TRUE, open="r")
        while (isIncomplete(con1))
            readLines(con1)
        close(con1)
    })
}     
d <- mcparallel(f())

тогда мы общаемся с ним, только один раз, и собираем результаты

con2 <- socketConnection(Sys.info()["nodename"], port = 6011)
writeLines("ok", con2)
close(con2)
mccollect(d)

что показывает мне, что раздвоенный процесс ждал в течение полутора секунд, пока я выполняются последующие команды

> mccollect(d)
$`28975`
   user  system elapsed 
  0.000   0.000   1.515 

Это было бы более законным, если бы процессы были отдельными, а не раздвоенными, как в задании MPI, где можно было бы использовать пакет Rmpi для связи между узлами.


Я не знаю, как использовать parallel, но утилиты tcltk работают таким образом, что кажется параллельным или фоновым для обычного цикла событий R. Вы можете использовать tclTaskSchedule функция из пакета tcltk2, чтобы сделать что-то вроде вашего выше цикла:

library(tcltk)
library(tcltk2)
tclTaskSchedule(1000, if( exists('a') ) { 
    tclTaskChange('WaitForA', redo=FALSE)
    cat('Success!\n\n')
    }, id='WaitForA',  redo=TRUE )

теперь вы можете делать другие вещи в R (в предположении a еще не существует), а в фоновом режиме выше будет проверять a примерно в 1 секунду. Как только вы создадите a (или примерно через секунду после этого), то - Успех! будет напечатано на экране (и он перестанет проверять).

обратите внимание, что это замена для использования parallel. По-видимому, tcltk и параллельные пакеты не играют хорошо вместе (похоже, что это было исправлено в R devel и исправлено, поэтому это может работать с parallel после R версии 2.15.3). Поэтому будьте осторожны, используя это, если вы также используете параллельный пакет для других вещей. Если parallel был просто вариантом, который вы пытались, и вы не используете его для других тогда этот метод должен работать нормально.