# Recommended way to cache results of expensive functions?

**URL:** <https://discourse.julialang.org/t/recommended-way-to-cache-results-of-expensive-functions/55239>\
**Category:** General Usage\
**Tags:** performance, design, optimization\
**Created:** [February 14, 2021, 3:04am UTC](https://discourse.julialang.org/t/recommended-way-to-cache-results-of-expensive-functions/55239 "2021-02-14T03:04:06Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![Shuhua](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/shuhua/32/27618_2.png) [@Shuhua](https://discourse.julialang.org/u/Shuhua)\
**Post date:** [February 14, 2021, 3:04am UTC](https://discourse.julialang.org/t/recommended-way-to-cache-results-of-expensive-functions/55239/1 "2021-02-14T03:04:06Z")

</div>

Suppose that I have a function `f: Int --> Float64` that conducts some expensive computation, but the integer inputs into `f` typically have only a very small number of possible values. I thus want to cache the results for speedup. In languages like C/C++, we may use a _local static variable_. What is the _Julian_ way to do this? A relevant topic is [Caching the results of a factory method](https://discourse.julialang.org/t/caching-the-results-of-a-factory-method/22483).

A straightforward method is to define a cache global variable in the enclosing module shown below.

```julia
module M

const cache = Dict{Int, Float64}()

function f(a::Int)
  if a ∉ keys(cache)
    # computate and store result in cache[a]
  end
  return cache[a]
end

end

```

However, if there are multiple functions that need cache, then there will be quite a few global variables like `cache1`, `cache2` that seem a little messy.

---

<div class="post-metadata">

**Author:** ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)\
**Post date:** [February 14, 2021, 3:10am UTC](https://discourse.julialang.org/t/recommended-way-to-cache-results-of-expensive-functions/55239/2 "2021-02-14T03:10:45Z")

</div>

> **[GitHub - JuliaCollections/Memoize.jl: ＠memoize macro for Julia](https://github.com/JuliaCollections/Memoize.jl)**
>
> ＠memoize macro for Julia. Contribute to JuliaCollections/Memoize.jl development by creating an account on GitHub.

try this?

---

<div class="post-metadata">

**Author:** ![ash](https://avatars.discourse-cdn.com/v4/letter/a/f19dbf/32.png) [@ash](https://discourse.julialang.org/u/ash)\
**Post date:** [February 14, 2021, 3:22am UTC](https://discourse.julialang.org/t/recommended-way-to-cache-results-of-expensive-functions/55239/3 "2021-02-14T03:22:34Z")

</div>

Or this

> **[GitHub - marius311/Memoization.jl: Easily and efficiently memoize any...](https://github.com/marius311/Memoization.jl)**
>
> Easily and efficiently memoize any function, closure, or callable object in Julia. - GitHub - marius311/Memoization.jl: Easily and efficiently memoize any function, closure, or callable object in J...

I don’t quite remember the differences but I’ve been using Memoization.jl in my code lately and it works great.

---

<div class="post-metadata">

**Author:** ![FPGro](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/fpgro/32/20822_2.png) [@FPGro](https://discourse.julialang.org/u/FPGro)\
**Post date:** [February 14, 2021, 7:43am UTC](https://discourse.julialang.org/t/recommended-way-to-cache-results-of-expensive-functions/55239/4 "2021-02-14T07:43:26Z")

</div>

Just for completeness: DefaultDict in DataStructures.jl  
[https://juliacollections.github.io/DataStructures.jl/latest/default\_dict/](https://juliacollections.github.io/DataStructures.jl/latest/default_dict/)  
Makes a good cache.

---

<div class="post-metadata">

**Author:** ![GunnarFarneback](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gunnarfarneback/32/1827_2.png) [@GunnarFarneback](https://discourse.julialang.org/u/GunnarFarneback)\
**Post date:** [February 14, 2021, 9:08am UTC](https://discourse.julialang.org/t/recommended-way-to-cache-results-of-expensive-functions/55239/5 "2021-02-14T09:08:10Z")

</div>

> [@Shuhua](#):
>
> However, if there are multiple functions that need cache, then there will be quite a few global variables like `cache1` , `cache2` that seem a little messy.

This is one way to solve that particular problem:

```julia
let cache = Dict{Int, Float64}()

    global function f(a::Int)
        if a ∉ keys(cache)
            # computate and store result in cache[a]
        end
        return cache[a]
    end
end
```

---

<div class="post-metadata">

**Author:** ![Shuhua](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/shuhua/32/27618_2.png) [@Shuhua](https://discourse.julialang.org/u/Shuhua)\
**Post date:** [February 14, 2021, 9:47am UTC](https://discourse.julialang.org/t/recommended-way-to-cache-results-of-expensive-functions/55239/6 "2021-02-14T09:47:13Z")

</div>

Thanks @GunnarFarneback . The above memoization packages are more convenient for result cache purposes in my original question. However, the `let` block version is more suitable for another scenario: to preallocate some memory in functions that are frequently used (i.e., in a for loop) but hide this detail from users.

```julia
let c = zeros(100)
    global function f(a::Vector, b::Vector)
        @assert length(a) == length(b) == 100
        c .= a .+ b
        # more operations on c
        # ...
    end
end

```

Previously, I usually pass `c` explicitly into the above function `f`, but removing `c` from the function interface seems much better.

---

<div class="post-metadata">

**Author:** ![GunnarFarneback](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gunnarfarneback/32/1827_2.png) [@GunnarFarneback](https://discourse.julialang.org/u/GunnarFarneback)\
**Post date:** [February 14, 2021, 9:52am UTC](https://discourse.julialang.org/t/recommended-way-to-cache-results-of-expensive-functions/55239/7 "2021-02-14T09:52:59Z")

</div>

> [@Shuhua](#):
>
> Previously, I usually pass `c` explicitly into the above function `f` , but removing `c` from the function interface seems much better.

Depends on how you use it. The obvious drawbacks are that you are limited to a fixed size and that it’s thread unsafe.
