R 闪亮的承诺/未来阻止进程 [英] R Shiny promise/future blocks process

查看:59
本文介绍了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 的很好的小插图.它也可以在 cranrstudio 博客.

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 闪亮的承诺/未来阻止进程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆