簡體   English   中英

帶有 invalidateLater() 的簡單 Shiny 應用程序錯誤地丟棄了持久后台進程

[英]Simple Shiny app with invalidateLater() incorrectly drops persistent background processes

我正在嘗試編寫一個最小的 Shiny 應用程序來維護一個持久的外部后台進程。 由於特定於全尺寸用例的原因,我正在跟蹤文本文件中的 PID,而不是僅使用processx句柄。 當我啟動應用程序時,它看起來像這樣:

在此處輸入圖像描述

當我按下“開始”按鈕時,應用程序會創建一個后台進程並將 PID 記錄在一個文本文件中。 帶有invalidateLater()的反應式上下文重復讀取文本文件並顯示 PID 和狀態。

在此處輸入圖像描述

該過程應該運行,直到我單擊“停止”。 但在初始化后不到一秒鍾,該進程自行退出。

在此處輸入圖像描述

如果我刪除invalidateLater() ,該過程將繼續運行。 或者,如果我使用processx句柄而不是ps和文本文件,則該應用程序可以工作,但這對於我的用例來說還不夠。

應用代碼

library(callr)
library(ps)
library(shiny)
library(tools)

ui <- fluidPage(
  actionButton("start", "start"),
  actionButton("stop", "stop"),
  textOutput("status")
)

server <- function(input, output, session) {
  file <- tempfile()
  observeEvent(input$start, {
    px <- r_bg(function() Sys.sleep(Inf))
    writeLines(as.character(px$get_pid()), file)
  })
  observeEvent(input$stop, {
    pid <- as.integer(readLines(file))
    if (pid %in% ps_pids()) {
      ps_kill(ps_handle(pid))
    }
  })
  output$status <- renderText({
    invalidateLater(100)
    if (file.exists(file)) {
      pid <- as.integer(readLines(file))
      paste(ifelse(pid %in% ps_pids(), "running", "stopped"), pid)
    }
  })
}

shinyApp(ui = ui, server = server)

Session 信息

R version 4.0.3 (2020-10-10)
Platform: x86_64-apple-darwin17.0 (64-bit)
Running under: macOS Catalina 10.15.7

Matrix products: default
BLAS:   /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib
LAPACK: /Library/Frameworks/R.framework/Versions/4.0/Resources/lib/libRlapack.dylib

locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8

attached base packages:
[1] tools     stats     graphics  grDevices utils     datasets  methods  
[8] base     

other attached packages:
[1] shiny_1.6.0 ps_1.5.0    callr_3.5.1

loaded via a namespace (and not attached):
 [1] Rcpp_1.0.6        magrittr_2.0.1    xtable_1.8-4      R6_2.5.0         
 [5] rlang_0.4.10      fastmap_1.1.0     jquerylib_0.1.3   htmltools_0.5.1.1
 [9] ellipsis_0.3.1    yaml_2.2.1        digest_0.6.27     lifecycle_1.0.0  
[13] processx_3.4.5    later_1.1.0.1     sass_0.3.1        promises_1.2.0.1 
[17] rsconnect_0.8.16  cachem_1.0.4      mime_0.10         compiler_4.0.3   
[21] bslib_0.2.4       jsonlite_1.7.2    httpuv_1.5.5   

編輯:垃圾收集

這是因為垃圾收集的processx句柄。 我可以通過 2 個 R 會話來證明這一點。 Session 1 創建一個后台進程。

px <- r_bg(function() Sys.sleep(Inf))
px$get_pid()
#> [1] 8252

Session 2 個循環檢查從 session 1 產生的后台進程。

library(ps)
while(TRUE) {
  print(8252 %in% ps_pids())
  Sys.sleep(1)
}

Session 2 從每秒打印TRUE開始。 但是當我調用rm(px); gc() Gc rm(px); gc()在 session 1, session 2 打印FALSE

我現在看到垃圾收集的終止是processx的故意功能: https://github.com/r-lib/processx#features 我猜在大多數情況下都是合理的。

如果我在callr::r_bg() cleanup設置為TRUE ,該過程將繼續進行。 問題解決了。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM