Как совместить 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 конечная точка?

0 ответов

Другие вопросы по тегам