The memoise package makes it easy to memoise R functions. Memoisation (https://en.wikipedia.org/wiki/Memoization) caches function calls so that if a previously seen set of inputs is seen, it can return the previously computed output.
Install from CRAN with
install.packages("memoise")
To memoise a function, use memoise()
:
library(memoise)
<- function(x) {
f Sys.sleep(1)
mean(x)
}<- memoise(f) mf
system.time(mf(1:10))
#> user system elapsed
#> 0.002 0.000 1.003
system.time(mf(1:10))
#> user system elapsed
#> 0.000 0.000 0.001
You can clear mf
’s cache with:
forget(mf)
And you can test whether a function is memoised with
is.memoised()
.
By default, memoise uses an in-memory cache, using
cache_mem()
from the cachem package.
cachem::cache_disk()
allows caching using files on a local
filesystem.
Both cachem::cache_mem()
and
cachem::cache_disk()
support automatic pruning by default;
this means that they will not keep growing past a certain size, and
eventually older items will be removed from the cache. The default size
cache_mem()
is 512 MB, and the default size for a
cache_disk()
is 1 GB, but this can be customized by
specifying max_size
:
# 100 MB limit
<- cachem::cache_mem(max_size = 100 * 1024^2)
cm
<- memoise(f, cache = cm) mf
You can also change the maximum age of items in the cache with
max_age
:
# Expire items in cache after 15 minutes
<- cachem::cache_mem(max_age = 15 * 60)
cm
<- memoise(f, cache = cm) mf
By default, a cache_disk()
uses a subdirectory the R
process’s temp directory, but it is possible to specify the directory.
This is useful for persisting a cache across R sessions, sharing a cache
among different processes, or even for synchronizing across the
network.
# Store in "R-myapp" directory inside of user-level cache directory
<- cachem::cache_disk(rappdirs::user_cache_dir("R-myapp"))
cd
# Store in Dropbox
<- cachem::cache_disk("~/Dropbox/.rcache") cdb
A single cache object can be shared among multiple memoised functions. By default, the cache key includes not only the arguments to the function, but also the body of the function. This essentially eliminates the possibility of a cache collision, even if two memoised functions are called with the same arguments.
<- cachem::cache_mem()
m
<- memoise(function(x) { x * 2 }, cache = m)
times2 <- memoise(function(x) { x * 4 }, cache = m)
times4
times2(10)
#> [1] 20
times4(10)
#> [1] 40
It is possible to use other caching backends with memoise. These caching objects must be key-value stores which use the same API as those from the cachem package. The following methods are required for full compatibiltiy with memoise:
$set(key, value)
: Sets a key
to
value
in the cache.$get(key)
: Gets the value associated with
key
. If the key is not in the cache, this returns an object
with class "key_missing"
.$exists(key)
: Checks for the existence of
key
in the cache.$remove(key)
: Removes the value for key
from the cache.$reset()
: Resets the cache, clearing all key/value
pairs.Note that the sentinel value for missing keys can be created by
calling cachem::key_missing()
, or
structure(list(), class = "key_missing")
.
Before version 2.0, memoise used different caching objects, which did not have automatic pruning and had a slightly different API. These caching objects can still be used, but we recommend using the caching objects from cachem when possible.
With the old-style caching objects, memoise first checks for the existence of a key in the cache, and if present, it fetches the value. This results in a possible race condition (when using caches other than the memory cache): an object could be deleted from the cache after the existence check, but before the value is fetched. With the new cachem-style caching objects, the possibility of a a race condition is eliminated: memoise simply tries to fetch the key, and if it’s not present in the cache, the cache returns a sentinel value indicating that it’s missing. (Note that the caching objects must also be designed to avoid a similar race condition internally.)
The following cache objects do not currently have an equivalent in cachem.
cache_s3()
allows caching on Amazon S3 Requires you to specify
a bucket using cache_name
. When creating buckets, they must
be unique among all s3 users when created.
Sys.setenv(
"AWS_ACCESS_KEY_ID" = "<access key>",
"AWS_SECRET_ACCESS_KEY" = "<access secret>"
)<- cache_s3("<unique bucket name>") cache
cache_gcs()
saves the cache to Google Cloud Storage.
It requires you to authenticate by downloading a JSON authentication
file, and specifying a pre-made bucket:
Sys.setenv(
"GCS_AUTH_FILE" = "<google-service-json>",
"GCS_DEFAULT_BUCKET" = "unique-bucket-name"
)<- cache_gcs() gcs