我正在使用 R 包制作 API plumber
。这个 API 中的一些端点会从记忆化中受益,所以我也使用了这个memoise
包。将两者结合起来非常简单,如本博文所示。我将在这篇文章的示例上建立我的代表。
# test.R
library(memoise)
# Define function ---------------------------------------------------------
add <- function(a, b) {
a + b
}
# Memoisize function ------------------------------------------------------
add_mem <- memoise(add)
# Define API --------------------------------------------------------------
#* Return the sum of two numbers
#* @param a The first number to add
#* @param b The second number to add
#* @get /add
function(a, b) {
add(as.numeric(a), as.numeric(b))
}
#* Return the sum of two numbers, use memoise cached results when applicable
#* @param a The first number to add
#* @param b The second number to add
#* @get /addWithMemoise
function(a, b) {
add_mem(as.numeric(a), as.numeric(b))
}
# R console 1
plumber::plumb(file="test.R")$run(port=50000)
#Running plumber API at http://127.0.0.1:50000
#Running swagger Docs at http://127.0.0.1:50000/__docs__/
# R console 2
httr::GET("http://localhost:50000/add?a=1&b=1") %>% content()
#[[1]]
#[1] 2
httr::GET("http://localhost:50000/addWithMemoise?a=1&b=1") %>% content()
#[[1]]
#[1] 2
所以现在,我想让我的 API 能够处理并发调用。为此,我将使用该promises
包,如本博文中所示。结合plumber
起来promises
也很简单:
# Added in test.R
library(promises)
#* Return the sum of two numbers, use promises
#* @param a The first number to add
#* @param b The second number to add
#* @get /addWithPromise
function(a, b) {
future_promise({
add(as.numeric(a), as.numeric(b))
})
}
我重新启动 API,然后我可以调用这个新端点:
# R console 2
httr::GET("http://localhost:50000/addWithPromise?a=1&b=1") %>% content()
#[[1]]
#[1] 2
现在我想添加一个混合所有内容的端点(plumber
和memoise
)promises
。
# Added in test.R
#* Return the sum of two numbers, use promises and memoise cached results when applicable
#* @param a The first number to add
#* @param b The second number to add
#* @get /addWithPromiseMemoise
function(a, b) {
future_promise({
add_mem(as.numeric(a), as.numeric(b))
})
}
我重新启动 API,然后调用它:
# R console 2
httr::GET("http://localhost:50000/addWithPromiseMemoise?a=1&b=1") %>% content()
#$error
#[1] "500 - Internal server error"
#
#$message
#[1] "Error in add_mem(as.numeric(a), as.numeric(b)): attempt to apply non-function\n"
# R console 1
#Unhandled promise error: attempt to apply non-function
#<simpleError in add_mem(as.numeric(a), as.numeric(b)): attempt to apply non-function>
我试图与future_promise
's 的envir
论点混在一起,但没有成功。我也试过这个:
# Added in test.R
#* Return the sum of two numbers, use promises and memoise cached results when applicable
#* @param a The first number to add
#* @param b The second number to add
#* @get /addWithPromiseMemoiseTest
function(a, b) {
print(names(environment(add_mem)))
e <- environment(add_mem)
future_promise({
Sys.sleep(10)
print(add_mem)
print(class(add_mem))
print(names(environment(add_mem)))
environment(add_mem) <- e
print(names(environment(add_mem)))
add_mem(as.numeric(a), as.numeric(b))
})
}
我重新启动 API,然后调用它:
# R console 2
httr::GET("http://localhost:50000/addWithPromiseMemoise?a=1&b=1") %>% content()
#[[1]]
#[1] 2
# R console 1
#[1] "_omit_args" "_hash" "_additional" "_default_args" "_f_hash" "_cache" "_f"
#Memoised Function:
#NULL
#[1] "memoised" "function"
# [1] "...future.startTime" "...future.oldOptions" "a" "b" "setdiff" "...future.rng" "e" "...future.frame"
# [9] "...future.conditions" "...future.mc.cores.old" "...future.stdout" "add_mem"
#[1] "_omit_args" "_hash" "_additional" "_default_args" "_f_hash" "_cache" "_f"
它返回正确的结果,并且该部分按预期工作(在端点调用中future_promise
添加 10s 后我可以看到,然后从另一个 R 会话调用另一个端点),但该部分似乎不起作用(我可以看到在函数中添加 10s后,两次调用最后一个端点并不会使其更快)。Sys.sleep
future_promise
future_promise
memoise
Sys.sleep
add
编辑:如果我将它与文件系统记忆结合起来,这个解决方案似乎有效:
# Changed in test.R
# Memoisize function ------------------------------------------------------
cache_fs <- cache_filesystem(".")
add_mem <- memoise(add, cache=cache_fs)
但它看起来确实不是一个干净的解决方案。
因此,由于这是一篇很长的帖子,我会清楚地说明我的问题,以防我失去你:
有没有一种干净的方式来组合memoise::memoise
和promises::future_promise
在plumber
端点内?