Hey, let’s talk about memoization.
I would like to address one of our coding habits. I notice that we have a tendency to overuse memoization. I would like to point out that memoization is a double edge sword and does not always yield expected results.
Here is an example. I pulled it from recent code I saw:
require 'benchmark'
require 'active_support/all'
EDUCATION_DURATION_ESTIMATE = 10.years
DEFAULT_STUDY_DEBT_DURATION = 15.years
def start_date_1
@start_date ||= (Date.new(2000, 01, 01) + EDUCATION_DURATION_ESTIMATE).to_datetime
end
def end_date_1
(start_date_1 + DEFAULT_STUDY_DEBT_DURATION).to_datetime
end
def start_date_2
(Date.new(2000, 01, 01) + EDUCATION_DURATION_ESTIMATE).to_datetime
end
def end_date_2
(start_date_2 + DEFAULT_STUDY_DEBT_DURATION).to_datetime
end
Benchmark.bm(20) do |x|
x.report('with memoizing:') do
start_date_1
start_date_1
end_date_1
end
x.report('without memoizing:') do
start_date_2
start_date_2
end_date_2
end
end
Code above executes two scenarios: With memoization Without memoization
Results:
user system total real
with memoizing: 0.000098 0.000023 0.000121 ( 0.000124)
without memoizing: 0.000038 0.000000 0.000038 ( 0.000038)
As you can see code without memoization is two times faster.
One of the most expensive operations for your computer is memory allocation. That is why you have loading screens in games and why you want to allocate most of your memory in constructor(initialiser).
To cache operations that require IO (database, http, files) To save computation that required
In the example above it takes a while when memoization wins. With trial and error I landed at 29-30 iterations when @start_date variable paid off.
Benchmark.bm(20) do |x|
x.report('with memoizing:') do
start_date_1
30.times { start_date_1 }
end_date_1
end
x.report('without memoizing:') do
start_date_2
30.times { start_date_2 }
end_date_2
end
end