2015-09-28 4 views
6

У меня есть общие функции, чтобы поймать все исключения включены в моем пакете logR::tryCatch2 определяется как:Invoke прерывания от R кода

tryCatch2 <- function(expr){ 
    V=E=W=M=I=NULL 
    e.handler = function(e){ 
     E <<- e 
     NULL 
    } 
    w.handler = function(w){ 
     W <<- c(W, list(w)) 
     invokeRestart("muffleWarning") 
    } 
    m.handler = function(m){ 
     attributes(m$call) <- NULL 
     M <<- c(M, list(m)) 
    } 
    i.handler = function(i){ 
     I <<- i 
     NULL 
    } 
    V = suppressMessages(withCallingHandlers(
     tryCatch(expr, error = e.handler, interrupt = i.handler), 
     warning = w.handler, 
     message = m.handler 
    )) 
    list(value=V, error=E, warning=W, message=M, interrupt=I) 
} 

Как вы можете видеть в последней строке она возвращает список, который более или менее самостоятельно описывая.
Это делает реальную реакцию на исключения задержанных после tryCatch2 вызова простым !is.null:

f = function(){ warning("warn1"); warning("warn2"); stop("err") } 
r = tryCatch2(f()) 
if(!is.null(r$error)) cat("Error detected\n") 
# Error detected 
if(!is.null(r$warning)) cat("Warning detected, count", length(r$warning), "\n") 
# Warning detected, count 2 

Он работает, как и ожидалось, я могу реагировать с моим собственным кодом. Но в некоторых случаях я бы не остановил процесс прерывания , который тоже пойман. На данный момент мне кажется, мне нужно добавить дополнительный параметр в tryCatch2, который будет контролировать, если прерывания должны быть уловом или нет. Таким образом, вопрос спрашивает о каком-то invokeInterrupt функции, которую я мог бы использовать следующим образом:

g = function(){ Sys.sleep(60); f() } 
r = tryCatch2(g()) 
# interrupt by pressing ctrl+c/stop while function is running! 
if(!is.null(r$interrupt)) cat("HERE I would like to invoke interrupt\n") 
# HERE I would like to invoke interrupt 

Я думаю, что если R способен поймать один он должен быть также способен вызывать один.
Как я могу достичь invokeInterrupt функциональности?

+0

Почему бы не изменить интерфейс? Вместо 'if (! Is.null (r $ interrupt))', предоставить функцию, чтобы пользователь выполнял 'if (r $ has_interrupt())', и вы можете вызвать прерывание в этой функции. –

+0

@KonradRudolph для этого мне все еще нужно знать, как вызвать прерывание из R-кода, не так ли? – jangorecki

+1

Ах, тогда я неправильно понял вопрос. Я действительно не знаю, как это сделать в R, и если я правильно понимаю некоторые документы, это может быть невозможно. –

ответ

3

Я могу предложить частичное решение, основанное на пакете tools.

invokeInterrupt <- function() { 
    require(tools) 
    processId <- Sys.getpid() 
    pskill(processId, SIGINT) 
} 

Тем не менее, следует помнить, что метание сигнал прерывания (SIGINT) с pskill не кажутся очень прочными. Я провел несколько тестов, посылая исключение и поймать его с функцией, например, так:

will_interrupt <- function() { 
    Sys.sleep(3) 
    invokeInterrupt() 
    Sys.sleep(3) 
} 

r = tryCatch2(will_interrupt()) 

В Linux это работало хорошо, когда выполняется из R командной строки. В окнах команда R и R Gui закрылись при выполнении этого кода. Хуже: на Linux и в Windows этот код разбился Rstudio мгновенно ...

Итак, если ваш код должен быть выполнен из командной строки R в Linux, это решение должно быть в порядке. В противном случае вам может быть не повезло ...

+0

Красивый трюк. В моем случае это не сработает, я хочу вызывать * прерывание * из функции низкого уровня, но позже сможет поймать его на несколько кадров выше в стеке вызовов, используя другой вызов 'tryCatch2'. – jangorecki

+0

Я еще не заметил 'SIGINT' (я не знал, что сигнал существует). Я протестировал его и, похоже, не поймал верхнее прерывание правильно. Половина щедрости кажется справедливой. Интересно, почему прерывание in-R отличается от сигнала SIGINT, и если оно не должно быть одинаковым? – jangorecki

+0

Мне бы хотелось увидеть лучшее решение, чем тот, который я опубликовал (что действительно специфично, поскольку оно работает только с Linux), поэтому да, не принимайте это решение, и давайте подождем, если кто-то может взломать эту проблему :) – Jealie

Смежные вопросы