将外部 类 与 Shiny、R 和期货一起使用
using external classes with Shiny, R and futures
我正在尝试构建一个框架,让 Shiny 在我拥有的一组 classes 上异步工作,使用 futures 和可能的 promises。我已经使用一组模拟我的真实设置的外部模块组合了一个测试项目。
注意:我还尝试实现与此框架中抛出错误完全相同的调用:FutureProcessor.R,并且返回的错误是相同的。
基本上,单击按钮会调用一个实例化 class 实例的函数,然后执行简单的计算。当 运行 将第一个按钮作为一个直接过程时,这工作正常。但是,当我 运行 它使用 %<-% 赋值时,它 returns 出现以下错误: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)
我的测试class:
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)
}
我认为在异步期货中使用引用 classes 存在一些问题,如 A Future for R: Common Issues with Solutions 中所述。
首先是缺少全局变量。 Future 在 运行 确定需要向 R 进程公开哪些全局变量之前静态检查代码。当您使用 new("classname")
实例化引用 class 对象时,直到 运行 时间(当 getClass()
被调用时)才知道实际的 class 定义,因此 future won '知道导出它。
一个最小的例子:
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
解决方法是使用 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
我对参考 classes 的了解还不足以解决这两个问题,因此我建议改用 R6 classes。在未来的表达中,它们似乎没有与参考 classes 相同的问题。
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)
我正在尝试构建一个框架,让 Shiny 在我拥有的一组 classes 上异步工作,使用 futures 和可能的 promises。我已经使用一组模拟我的真实设置的外部模块组合了一个测试项目。
注意:我还尝试实现与此框架中抛出错误完全相同的调用:FutureProcessor.R,并且返回的错误是相同的。
基本上,单击按钮会调用一个实例化 class 实例的函数,然后执行简单的计算。当 运行 将第一个按钮作为一个直接过程时,这工作正常。但是,当我 运行 它使用 %<-% 赋值时,它 returns 出现以下错误: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)
我的测试class:
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)
}
我认为在异步期货中使用引用 classes 存在一些问题,如 A Future for R: Common Issues with Solutions 中所述。
首先是缺少全局变量。 Future 在 运行 确定需要向 R 进程公开哪些全局变量之前静态检查代码。当您使用 new("classname")
实例化引用 class 对象时,直到 运行 时间(当 getClass()
被调用时)才知道实际的 class 定义,因此 future won '知道导出它。
一个最小的例子:
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
解决方法是使用 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
我对参考 classes 的了解还不足以解决这两个问题,因此我建议改用 R6 classes。在未来的表达中,它们似乎没有与参考 classes 相同的问题。
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)