R 闪亮的承诺/未来阻止进程

编程入门 行业动态 更新时间:2024-10-23 03:23:46
本文介绍了R 闪亮的承诺/未来阻止进程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

尽管尝试使用异步 future + promises 策略,但我无法找出导致 Shiny 进程阻塞的脚本逻辑中的错误.

I cannot figure out the fault in my script's logic that causes Shiny process blocking despite trying to use async future + promises strategy.

我有这个(简化的)服务器脚本.它原则上有效,但我没有经历并行化.我模拟了 2 个同时触发,第二个触发事件等待第一个事件解决.

I have this (simplified) server script. It works in principle, but I don't experience parallelization. I simulate 2 simultaneous triggering and the second triggering event waits until the first one resolves.

你能指出这里有什么问题吗?我已经阅读了好几本手册,但我仍然很难确定逻辑.

Can you please indicate what is wrong here? I have read several manuals, but I still find it hard to nail down the logic.

最小示例,单文件 Shiny 应用程序:

Minimal Example, a one-file Shiny app:

## load libs library(shiny) library(DT) library(ggplot2) ui <- navbarPage( tabPanel( "Новостные тренды" , sidebarLayout( sidebarPanel( br() , actionButton( "run_trends" , label = "run" , style="color: #fff; background-color: #337ab7; border-color: #2e6da4" ) , br() ) , mainPanel( textOutput("trends_time") , br() , br() , plotOutput('trend_plotly') , br() , p("results") , br() , DTOutput('trend_tbl') , br() , br() ) ) ) ) server <- function(input, output, session) { dt_trend <- observeEvent( input$run_trends, { ## load libs library(data.table) library(ggplot2) library(promises) library(future) plan(multiprocess) dat_func <- function() { start_time <- Sys.time() dt <- data.table(x = rnorm(100), y = rnorm(100)) trendy_tbl <- head(dt, 10) ggplo1 <- ggplot(dt) + geom_point(aes(x=x,y=y)) Sys.sleep(10) list( trendy_tbl , ggplo1 , paste0('time: ', round(Sys.time() - start_time), ' сек.') ) } f <- future({ dat_func() }) #res <- future::value(f) output$trend_tbl <- renderDT({future::value(f)[[1]]}) output$trend_plotly <- renderPlot({future::value(f)[[2]]}) output$trends_time <- renderText({future::value(f)[[3]]}) }) } # Return a Shiny app object shinyApp(ui = ui, server = server, options = list(port = 4600, host = '0.0.0.0'))

推荐答案

试试这个:

library(data.table) library(ggplot2) library(promises) library(future) plan(multiprocess) server <- function(input, output, session) { dt_trend <- eventReactive( input$run_trends, { dat_func <- function() { start_time <- Sys.time() dt <- data.table(x = rnorm(100), y = rnorm(100)) trendy_tbl <- head(dt, 10) ggplo1 <- ggplot(dt) + geom_point(aes(x=x,y=y)) Sys.sleep(10) list( trendy_tbl , ggplo1 , paste0('time: ', round(Sys.time() - start_time), ' сек.') ) } # Returning future future({ dat_func() }) }) output$trend_tbl <- renderDT({dt_trend()[[1]]}) output$trend_plotly <- renderPlot({dt_trend()[[2]]}) output$trends_time <- renderText({dt_trend()[[3]]}) }

关键思想是:

  • 确保您使用引入了异步支持的 shiny 版本 > 1.1.0(2018 年 4 月).
  • 不要使用 future::value,因为它会阻塞并等待未来,这正是我们想要避免的.
  • 相反,在 reactive 中返回未来.在这种情况下,这意味着使用 eventReactive 而不是 observeEvent.
  • 通过反应式访问未来的价值.请注意,您的反应价值现在是未来!这意味着您需要使用未来的处理程序来使用该值.(*)
  • 您还可以在任何 renderXXX 函数中返回一个 future.例如,如果您有大量耗时的绘图,则很有用.
  • Make sure you use shiny version > 1.1.0 (April 2018) which introduced async support.
  • do NOT use future::value as it blocks and waits for the future, precisely what we want to avoid.
  • instead, return the future in a reactive. In this case, this means using eventReactive instead of observeEvent.
  • Access the value of the future via the reactive. Note that your reactive value is now a future! This means you need to use future handlers to use the value. (*)
  • You can also return a future in any renderXXX function. Useful for example if you have large time-consuming plots.

(*) 实际上,这意味着你需要做

(*) In practice, this means you need to do

renderDT(dt_trend() %>% then(~.[[1]])) # or renderDT(dt_trend() %>...% `[[`(1))

其中 then 来自 promises 包,[[ 是基础 R (x[[i]] 实际上是`[[`(x, i) !).

where then is from the promises package and [[ is the subsetting function from base R (x[[i]] is actually semantic sugar for`[[`(x, i) !).

在您的示例中,您基本上计算了 dt_trend 中单个 future 中的所有内容.您可能需要考虑使用多个小型期货.你可以在一个带有未来的反应式中加载数据,然后将输出代码保存在你的 renderXXX 函数中,如果需要的话,包装在 future 中.

In your example, you basically compute everything in a single future in dt_trend. You may want to consider using multiple small futures instead. You can load the data in a reactive with a future, then keep the output code in your renderXXX functions, wrapped in a future if needed.

通过运行 vignette("shiny", package = "promises")(**),有一个关于使用具有闪亮可用的 Promise 的很好的小插图.它也可以在 cran 或rstudio 博客.

There is a good vignette on using promises with shiny available by running vignette("shiny", package = "promises")(**). It is also available online on cran or on the rstudio blog.

(**) 如果您使用 install_github("rstudio/promises") 安装了 promise,您很可能必须先使用 build_vignettes = TRUE 重新安装.

(**) If you installed promises with install_github("rstudio/promises"), you most likely have to re-install with build_vignettes = TRUE first.

更多推荐

R 闪亮的承诺/未来阻止进程

本文发布于:2023-11-25 02:47:08,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1628015.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:进程   未来

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!