Как совместить future_promise с memoise в R водопроводчик
Я делаю API с пакетом R. Некоторые конечные точки в этом API выиграют от мемоизации, поэтому я также использую пакет. Объединение обоих довольно просто, как показано в этом сообщении в блоге. Я буду использовать пример этого поста для своего репрекса.
# 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 возможность обрабатывать одновременные вызовы. Для этого я буду использовать пакет, как показано в этом сообщении в блоге. Комбинирование с довольно просто:
# 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
Теперь я хочу добавить конечную точку, которая смешивает все (, и
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>
Я пытался смешаться с
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"
Он возвращает правильный результат, и часть работает так, как ожидалось (это я вижу после добавления 10 с в вызове конечной точки, а затем вызова другого
future_promise
конечная точка из другого сеанса R), но
memoise
часть не работает (это я вижу после добавления 10s
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
конечная точка?