nI想使用memoization來緩存某些昂貴操作的結果,以免它們一遍又一遍地被重複計算。R:緩存/環境備份
memoise和3210符合我的需求。但是,我發現緩存在呼叫中不穩健。
下面是一個說明我看到了問題的一個例子:基於答案
library(memoise)
# Memoisation works: b() is called only once
a <- function(x) runif(1)
replicate(5, a())
b <- memoise(a)
replicate(5, b())
# Memoisation fails: mfn() is called every single time
ProtoTester <- proto(
calc = function(.) {
fn <- function() print(runif(1))
mfn <- memoise(fn)
invisible(mfn())
}
)
replicate(5, ProtoTester$calc())
更新
這個問題可以基於持久或非持久的緩存是否有不同的答案用過的。非永久性緩存(例如memoise
)可能需要單獨分配,然後下面的答案是一個不錯的方法。持久性緩存(例如R.cache
)適用於多個分配,應該是對於多個分配的健壯性。上述方法適用於R.cache
。儘管有多個作業,fn
只能用R.cache
調用一次。它將被調用memoise
兩次。
> ProtoTester <- proto(
+ calc = function(.) {
+ fn <- function() print(runif(1))
+ invisible(memoizedCall(fn))
+ }
+)
> replicate(5, ProtoTester$calc())
[1] 0.977563
[1] 0.1279641
[1] 0.01358866
[1] 0.9993092
[1] 0.3114813
[1] 0.97756303 0.12796408 0.01358866 0.99930922 0.31148128
> ProtoTester <- proto(
+ calc = function(.) {
+ fn <- function() print(runif(1))
+ invisible(memoizedCall(fn))
+ }
+)
> replicate(5, ProtoTester$calc())
[1] 0.97756303 0.12796408 0.01358866 0.99930922 0.31148128
爲什麼我認爲我有一個問題,R.cache
的原因是,我傳遞一個proto
方法的功能memoizedCall
。 proto
方法被綁定到環境的方式,R.cache
很難。在這種情況下你必須做的是取消綁定函數(從實例化的方法獲得一個簡單的函數),然後手動傳遞該對象作爲第一個參數。下面的示例演示如何工作(包括Report
和Report$loader
是proto
對象:
# This will not memoize the call
memoizedCall(Report$loader$download_report)
# This works as intended
memoizedCall(with(Report$loader, download_report), Report$loader)
我很想知道爲什麼R.cache
作品綁定到環境中的正常功能,但無法與proto
實例化的方法
我誤解了memoise實現使用的對象標識機制。因爲'R.緩存'具有與記憶相關的持久性我認爲它的設計基於功能的內容/代碼而不是其內部的R ID,否則它不會跨會話工作。以memoization作爲副作用創建表達式是一個很好的模式。你的代碼甚至可以在任務分配(多次執行多次分配'fn'的ProtoTester分配)時使用'R.cache'工作。我想知道爲什麼它以前不適合我... – Sim 2012-07-06 16:18:39
我再次檢查並發現'R.cache'與我的舊代碼一起工作。我一定忽略了一件簡單的事情。 – Sim 2012-07-06 16:20:58
我更新了問題並澄清了涉及持久性時的行爲差異。 – Sim 2012-07-06 16:33:52