2011-11-11 10 views
15

Sto usando sempre più Rscript dove avrei normalmente usato gli script di bash. Un piccolo fastidio è che molti di questi script eseguono il ciclo su alcune chiamate system() che non lasciano praticamente il tempo necessario a R per catturare il mio controllo-c se provo a interromperlo. Invece interrompe semplicemente il comando di sistema che era in esecuzione e continua alla successiva iterazione del ciclo. Ad esempio, quando si tenta di interrompere il seguente tenendo premuto control-c, si fa ancora attraverso tutte le iterazioni:Interrupt loop con comando di sistema

for(i in 1:10) { 
    cat(i) 
    system('sleep 3') 
} 

Finora sono sempre appena violato risolvere questo inserendo una piccola pausa in ogni ciclo come

for(i in 1:10) { 
    Sys.sleep(0.25) 
    cat(i) 
    system('sleep 3') 
} 

che mi permetta di abortire all'interno di un'iterazione o due se tengo premuto control-c, ma mi chiedo, c'è un modo più efficiente per eseguire questo comportamento?

+0

Ottima domanda. Ho letto alcuni dei guRus dire che qualsiasi programma ben scritto sarà in ascolto di una battuta d'arresto, ma sembra che molti (e certamente tutti i miei) non siano scritti con quella caratteristica. –

+0

Anche qui! Mi infastidisce perché questi script di manutenzione sono di solito per impostare le aree della directory degli esperimenti, quindi usa molti comandi molto veloci 'mkdir',' chmod', 'ln', ecc. Ma quando devo farlo per 1000 soggetti, anche solo con una pausa di 0,25 secondi ci sono circa 5 minuti ogni volta che ne eseguo uno. –

+0

Il ciclo AFAIK an R non è un processo separato, quindi '% kill-9 $ PID' non funzionerà. Ma fammi chiedere: che cosa hai esattamente bisogno di uccidere? Se è un loop over, ad esempio 1: 10000, è possibile inserire un prompt() che viene eseguito ogni 1000 cicli. Se stai eseguendo uno script che è semplicemente molto lungo e hai cambiato idea dopo averlo avviato, beh, è ​​proprio colpa tua :-). –

risposta

3

John, non sono sicuro che ciò possa essere d'aiuto, ma dall'investigare setTimeLimit, ho appreso che può fermare l'esecuzione ogni volta che un utente è in grado di eseguire un interrupt, come Ctrl-C. Vedi this question per alcuni riferimenti.

In particolare, le richiamate possono essere la strada da percorrere, e vorrei controllare addTaskCallback e this guide on developer.r-project.org.

Ecco altri quattro suggerimenti:

  1. Anche se è un hack, un approccio molto diverso il mio essere di invocare due sessioni R, uno è una sessione di master e l'altro esiste semplicemente per eseguire comandi di shell passavano la sessione principale, che attende solo una conferma che il lavoro è stato fatto prima di iniziare il successivo.

  2. Se è possibile utilizzare foreach invece di for (sia in parallelo, tramite% Dopar%, o% serial fare% anziché% Dopar% oppure solo 1 lavoratore iscritto w /), questo può essere più suscettibili di interruzioni, come può essere equivalente al primo suggerimento (dal momento che si biforca R).

  3. Se è possibile recuperare il codice di uscita per il comando esterno, è possibile passare a un ciclo condizionale. This previous Q&A sarà utile in tal senso.

  4. Se si desidera che tutto venga eseguito in uno script bash, allora R potrebbe semplicemente scrivere uno script lungo (ad esempio, generare una stringa o una serie di stringhe su un file). Questo potrebbe essere eseguito e l'interrupt è garantito non influenzare un ciclo, come hai srotolato il ciclo. In alternativa, puoi scrivere loop in bash. Here are examples. Personalmente, mi piace applicare i comandi ai file usando find (ad esempio find .... -exec doStuff {} ';') o come input tramite backquote. Sfortunatamente, non posso dare facilmente un codice ben formattato su SO, poiché incorpora i backquote all'interno dei backquote ... See this page for examples Quindi, potrebbe essere il caso che tu possa avere un comando, nessun loop e applicare una funzione a tutti i file soddisfare una particolare serie di criteri. L'uso della sostituzione di comando tramite backquote è un trucco molto utile per un utente bash.

+0

Grazie per questo, @Iterator. Lo sto masticando un po 'di più in fondo alla mente negli ultimi due giorni. L'infrastruttura di callback sembra promettente. Sono preoccupato, tuttavia, che si verificherà lo stesso problema che mi impedisce di utilizzare l'idea di DWin sopra: non conosco una funzione che "controlla la pressione di un tasto" o "controlla la presenza di un pulsante" o qualcosa di simile quella. Ho sicuramente bisogno di leggere un po 'di quella documentazione più da vicino, dato che ci sono alcuni dettagli ... –

+0

anche gli altri suggerimenti saranno utili. # 1 e 2 in particolare per gli script più lunghi, in cui utilizzo già il nostro programmatore di cluster che è facile da eliminare. Per i piccoli e semplici script, tuttavia, vorrei ancora che ci fosse un modo più semplice. # 3 Penso che sarà particolarmente utile, poiché molti di questi strumenti emettono uno stato anomalo se vengono interrotti. –

+0

Dopo tutto questo, però, mi chiedo se sto cercando troppo difficile di inserire un piolo quadrato in un buco rotondo. È così facile da fare 'for i in 1 ... n; fare ...; fatto in bash che per situazioni che * sono * così semplici, forse dovrei limitarmi a farlo? Non so ... –

0

È necessario verificare che ogni chiamata a system() abbia uno stato di uscita diverso da zero. Se si verifica un errore imprevisto, il programma deve essere stop() oppure è possibile ottenere risultati imprevisti. I programmi che chiami dovrebbero restituire uno stato di uscita diverso da zero quando vengono uccisi con Ctrl + C e, in caso contrario, si tratta di un bug o difetto in quei programmi.

+0

In realtà ho appena provato questo con '(system (" sleep "," 40 "))' che non indica un errore, anche se farlo all'interno di Bash lo fa, quindi forse la mia affermazione sopra è sbagliata. –

Problemi correlati