Viitoare: întreruperi, blocări și reîncercări

URMĂREȘTE-NE
16,065FaniÎmi place
1,142CititoriConectați-vă

(Acest articol a fost publicat pentru prima dată pe JottR pe Rși cu amabilitate a contribuit la R-bloggeri). (Puteți raporta problema legată de conținutul acestei pagini aici)


Doriți să vă distribuiți conținutul pe R-bloggeri? dați clic aici dacă aveți un blog, sau aici dacă nu aveți.

Întreruperi 🛑, blocări 💥, reîncercări 🔁

The viitor pachetul sărbătorește zece ani pe CRAN începând cu 19 iunie 2025. M-am blocat puțin în timpul sărbătorilor și în timp ce participam la fantasticul utilizator! conferință din 2025, dar, așa cum am promis, iată a patra dintr-o serie de postări pe blog care evidențiază îmbunătățirile recente aduse
viitorverse ecosistem.

TL;DR

În trecut, viitoarele care au fost întrerupte sau întrerupte brusc puneau probabil viitorul ecosistem într-o stare coruptă, în care trebuia să reporniți manual viitorul backend. Acest lucru nu mai este necesar;

  1. Futures gestionează acum întreruperile de evaluare

  2. Futures gestionează acum concedierile abrupte paralele de lucrători („crashuri”)

  3. Lucrătorii prăbușiți sunt reporniți automat

Întreruperi 🛑

Mai jos este un viitor care emulează o expresie R întreruptă la mijlocul evaluării:

library(future)

f <- future({ a <- 42; rlang::interrupt(); 2 * a })

Dacă încercăm să recuperăm valoarea acestui viitor, obținem:

v <- value(f)
#> Error: A future () of class SequentialFuture was interrupted
#> at 2025-10-15T15:37:09, while running on 'localhost' (pid 530375)

Acest lucru funcționează la fel pentru toate backend-urile viitoare, de ex

plan(future.mirai::mirai_multisession)
f <- future({ a <- 42; rlang::interrupt(); 2 * a })
v <- value(f)
#> Error: A future () of class MiraiMultisessionFuture was
#> interrupted at 2025-10-15T15:39:17, while running on 'localhost' (pid 531734)

Este neobișnuit ca R să se întrerupă astfel, dar se poate întâmpla dacă
plan(sequential) este folosit și utilizatorul apasă Ctrl-C
(comun) sau trimite kill -SIGINT (mai puțin frecvente).

Există și alte modalități de a întrerupe un viitor – mai multe despre asta într-o postare viitoare.

Muncitori prăbușiți 💥

Mai jos este un viitor care emulează un lucrător paralel care încetează brusc („crash”) în timpul evaluării:

library(future)
plan(multisession)

f <- future({ a <- 42; tools::pskill(Sys.getpid()); 2 * a })

Aici tools::pskill(Sys.getpid()) oprește procesul de lucru R care evaluează apelul. În practică, un muncitor se poate prăbuși din diverse motive. De exemplu,

  • Procesul R poate rămâne fără memorie și să fie ucis de sistemul de operare („OOM killer”)

  • Într-un mediu HPC, planificatorul de job ar putea termina lucrătorul dacă depășește limitele de memorie sau de rulare

  • Utilizatorul poate ucide manual lucrătorul (de exemplu, kill -SIGQUIT
    ) sau anulați lucrarea HPC (scancel sau qdel
    )

Indiferent de modul în care lucrătorul paralel este terminat, solicitarea valorii produce:

v <- value(f)
#> Error: Future () of class MultisessionFuture interrupted,
#> while running on 'localhost' (pid 538181)

Din punct de vedere tehnic, această eroare moștenește și FutureInterruptErrorla fel ca atunci când există o întrerupere a utilizatorului. Acest comportament este consecvent în toate backend-urile, deși unele oferă mesaje de eroare mai detaliate.

Lucrătorii blocați sunt reporniți automat de viitorul backend, ceea ce înseamnă că nu mai trebuie să reporniți manual backend-ul pentru a realiza același lucru.

Rețineți că numai lucrătorul este repornit – viitorul însuși este nu.

Reîncercarea unui viitor întrerupt 🔁

Indiferent de motivul pentru care un viitor a fost întrerupt, îl puteți reporni apelând mai întâi reset()apoi declanșând reevaluarea prin
resolved() sau value().

De exemplu, luați în considerare o funcție problematică care blochează lucrătorul aproximativ 50% din timp:

problematic_fcn <- function(x) {
  if (proc.time()(3) %% 1 < 0.5)
    tools::pskill(Sys.getpid())
  sqrt(x)
}

Dacă chemați un lucrător paralel, am putea reîncerca, să zicem, de până la zece ori, înainte de a renunța:

library(future)
plan(multisession)

f <- future({ problematic_fcn(9) })

for (kk in 10:1) 
  tryCatch({
    v <- value(f)
    break
  }, FutureInterruptError = function(e) {
    if (kk == 1) stop(e)
    message("future interrupted, retrying ...") 
    f <- reset(f)
  })
}

message("value: ", v)

Acest lucru ar putea avea ca rezultat:

future interrupted, retrying ...
future interrupted, retrying ...
future interrupted, retrying ...
value: 3

Este un exercițiu distractiv să scrieți o funcție de ajutor future_retry() pentru a simplifica acest lucru ca:

f <- future_retry({ problematic_fcn(9) }, times = 10)
message("value: ", v)

Fie ca viitorul să fie cu tine!

Henrik

Dominic Botezariu
Dominic Botezariuhttps://www.noobz.ro/
Creator de site și redactor-șef.

Cele mai noi știri

Pe același subiect

LĂSAȚI UN MESAJ

Vă rugăm să introduceți comentariul dvs.!
Introduceți aici numele dvs.