首页 > 解决方案 > 使用 Future 包在 R 中进行异步编程

问题描述

我是使用 Future 包在 R 中进行异步编程的新手,因此需要一些帮助。我正在尝试使用支持异步编程的 rshiny 构建一个简单的应用程序。所以我的代码作为一个直方图、一个滑块、一个简单的文本打印和 read.csv 函数来读取一个大的 CSV 文件。所以我的计划是在我的 read.csv 函数使用 R 中的 future 包在后台运行之前,我想控制我的其他应用程序。

但我的代码等待读取 CSV 文件。任何帮助将不胜感激。代码示例如下。

library(promises)
library(future)
library(shinydashboard)
library(shiny)
library(tidyverse)
plan(multiprocess)

#UI parts
ui <- dashboardBody(fluidRow(box(tableOutput("input1")),
                             box(textOutput("input2"))),

                    fluidRow(box(
                      sliderInput(
                        inputId = "bins",
                        label = "Number of bins:",
                        min = 1,
                        max = 5,
                        value = 2
                      )
                    ),
                    box(plotOutput(outputId = "distPlot"))),


                    fluidRow(box(
                      sliderInput(
                        "slider2",
                        label = h3("Slider Range"),
                        min = 0,
                        max = 100,
                        value = c(40, 60)
                      )
                    ),
                    box(verbatimTextOutput("range"))))

#server part
server <- function(input, output, session) {
  output$input1 <- renderTable({
    promise <- future((read.csv("data/sample_large.csv")))
    promise %...>% head() %...>% print()
  })

  output$input2 <- renderText({
    print("hello")
  })
  output$distPlot <- renderPlot({
    dist <- rnorm(input$bins)
    hist(dist)
  })
  output$range <- renderPrint({
    input$slider2
  })

}
shinyApp(ui = dashboardPage(dashboardHeader(),
                            dashboardSidebar(),
                            ui),
         server = server)

标签: rasynchronouspromisefuture

解决方案


在评估承诺之前,您遇到的其他 UI 未加载的行为是预期行为。它在 promises 包中作为他们所谓的“闪亮刷新周期”的一部分进行了解释,并在此处此处进行了更详细的描述。

只有在所有输出都完成执行后,它们才会被发送回 Shiny 以更新 UI。您可能希望/更喜欢输出准备好后立即渲染,但不幸的是,这不是 Shiny 的操作方式。

如第二个链接中所述,您可以“欺骗”闪亮认为所有输出都已执行,然后在评估承诺后使用反应值触发最终更新:

#server part
server <- function(input, output, session) {

  data <- reactiveVal()

# Return NULL from this operation so Shiny 'thinks' the output is evaluated
  observe({
    data(NULL)
    future({read.csv("data/sample_large.csv")}) %...>%
      data() #Assign to data
    NULL
  })

# When data() is updated as a side effect of our promise the table will be updated
  output$input1 <- renderTable({
    req(data()) %>%
      head(5) %>%
      print()
  })

# in the mean time all outputs will be judged to be complete so can be rendered
  output$input2 <- renderText({
    print("hello")
  })
  output$distPlot <- renderPlot({
    dist <- rnorm(input$bins)
    hist(dist)
  })
  output$range <- renderPrint({
    input$slider2
  })

}
shinyApp(ui = dashboardPage(dashboardHeader(),
                            dashboardSidebar(),
                            ui),
         server = server)

推荐阅读