используя внешние классы с Shiny, R и фьючерсами - PullRequest
0 голосов
/ 19 октября 2018

Я пытаюсь собрать каркас, чтобы Shiny работал асинхронно с набором классов, которые у меня есть, используя фьючерсы и, возможно, обещания.Я собрал тестовый проект с использованием набора внешних модулей, которые имитируют мою реальную настройку.

Примечание. Я также пытался реализовать точно такой же вызов, который вызывает ошибку в этой среде: FutureProcessor.R , и возвращаемая ошибка идентична.

По сути, нажатие кнопки вызывает функцию, которая создает экземпляр класса, который затем выполняет простой расчет.При запуске с первой кнопкой как прямой процесс, это работает нормально.Однако, когда я запускаю его с использованием% <-%, он возвращает следующую ошибку: <code>Warning: Error in getClass: "cTest" is not a defined class

Мне ясно, что я не понимаю это правильно!Однако я не уверен, что то, что я пытаюсь сделать, вообще возможно?

Настройка выглядит следующим образом:

Блестящее приложение:

## Load required libraries
pacman::p_load(shiny, here, promises, future)

setwd(here())
source(here("testing.R"))
source(here("TestClass.R"))
plan(multisession)

# Define UI
ui <- fluidPage(

   # Application title
   titlePanel("Test external classes"),

   # Sidebar 
   sidebarLayout(
      sidebarPanel(
         actionButton("clickMe", "I work"),
         actionButton("clickMeToo", "I don't work")
      ),

      # Show a text output
      mainPanel(
         verbatimTextOutput("outputText1"),
         verbatimTextOutput("outputText2")
      )
   )
)

# Define server logic 
server <- function(input, output) {

  myResult <- NULL

   observeEvent(input$clickMe, {

     ## This works:
      myResult <<- testFutures()
      output$outputText1 <- renderText({paste0("test: ", myResult$Item3)})

   })
   observeEvent(input$clickMeToo, {
     ## This works not:
     myResult %<-% {testFutures()}
     output$outputText2 <- renderText({paste0("test: ", myResult$Item3)})
   })
}

# Run the application 
shinyApp(ui = ui, server = server)

Мой тестовый класс:

cTest <- setRefClass("cTest", 
                                     fields=list(

                                       Item1="numeric",
                                       Item2="numeric",
                                       Item3= "numeric"),

                                     methods = list(
                                       Reset = function() {
                                         Item1 <<- 0
                                         Item2 <<- 0
                                         Item3 <<- 0
                                       },
                                       AddUp = function() {
                                         Item3 <<- Item1 + Item2
                                       }
                                     )

Моя тестовая функция:

testFutures <- function() {
  output <- new ("cTest")
  output$Reset()
  output$Item1 <- 3
  output$Item2 <- 4
  output$AddUp()
  return(output)
}

1 Ответ

0 голосов
/ 24 октября 2018

Я думаю, что есть несколько проблем с использованием ссылочных классов в асинхронных фьючерсах, как описано в A Future for R: Общие проблемы с решениями .

Первая проблема связана с отсутствием глобальных переменных.Будущее статически проверяет код перед запуском, чтобы выяснить, какие глобальные переменные ему необходимо представить процессу R.Когда вы создаете экземпляр объекта ссылочного класса, используя new("classname"), фактическое определение класса неизвестно до времени выполнения (когда вызывается getClass()), поэтому в будущем не будет известно об его экспорте.

Минимальный пример:

library(future)

plan(multisession)

RefClassTest <- setRefClass("RefClassTest",
  fields = list(x = "numeric"),
  methods = list(get = function() x)
)

result %<-% new("RefClassTest")
result
## Error in getClass(Class, where = topenv(parent.frame())) :
##   "RefClassTest" is not a defined class

Обходной путь может заключаться в создании экземпляра с использованием генератора классов, например RefClassTest$new().Однако теперь вы столкнулись с проблемой экспорта генератора, поскольку (я думаю) он использует внешние указатели внутри.Объект не совсем правильно построен.

options(future.globals.onReference = "warning")

result %<-% RefClassTest$new()
## Warning message:
##   In FALSE :
##   Detected a non-exportable reference (‘externalptr’) in one of the globals (‘RefClassTest’ of class ‘refObjectGenerator’) used in the future expression

result
## Prototypical reference class object

result$get()
## Error in result$get() : object 'x' not found

Я недостаточно знаю справочные классы, чтобы обойти обе проблемы, поэтому я бы предложил вместо этого использовать классы R6.Похоже, они не имеют тех же проблем, что и ссылочные классы в будущих выражениях.

R6Test <- R6::R6Class("R6Test",
  public = list(
    x = numeric(0),
    get = function() self$x
  )
)

result %<-% {
  R6Test$new()
}

result
## <R6Test>
##   Public:
##   clone: function (deep = FALSE)
##     get: function ()
##       x:

result$get()
## numeric(0)
...