Just-in-Time vs Ahead-of-Time

Just-in-time and ahead-of-time are two different approaches for deciding when to do work.

Say we're writing a function that takes in a number n between 2 and 1,000 and checks whether the number is prime.

One option is to do the primality check when the function is called:

from math import sqrt def is_prime_brute_force(n): highest_possible_factor = int(sqrt(n)) for potential_factor in range(2, highest_possible_factor + 1): if n % potential_factor == 0: return False return True def is_prime(n): return is_prime_brute_force(n)

This is a just-in-time approach, since we only test a number when we've received it as input. (We determine whether n is prime "just in time" to be returned to the caller.)

Another option is to generate all the primes below 1,000 once and store them in a set. Later on, when the function is called, we'll just check if n is in that set.

from math import sqrt def is_prime_brute_force(n): highest_possible_factor = int(sqrt(n)) for potentialFactor in range(2, highest_possible_factor + 1): if n % potentialFactor == 0: return False return True primes = set() for potential_prime in range(2, 1001): if is_prime_brute_force(potential_prime): primes.add(potential_prime) def is_prime(n): return n in primes

Here we're taking an ahead-of-time approach, since we do the calculations up front before we're asked to test any specific numbers.

So, what's better: just-in-time or ahead-of-time? Ultimately, it depends on usage patterns.

If you expect is_prime will be called thousands of times, then a just-in-time approach will do a lot of repeat computation. But if is_prime is only going to be called twice, then testing all those values ahead-of-time is probably less efficient than just checking the numbers as they're requested.

Decisions between just-in-time and ahead-of-time strategies don't just come up in code. They're common when designing systems, too.

Picture this: you've finished a question on Interview Cake and triumphantly click to advance to the next question: Binary Search Tree Checker. Your browser issues a request for the question in Python 3.6.

There are a few possibilities for what happens on our server:

  • One option would be to store a basic template for Binary Search Tree Checker as a starting point for any language. We'd fill in this template to generate the Python 3.6 version when you request the page. This is a just-in-time approach, since we're waiting for you to request Binary Search Tree Checker in Python 3.6 before we do the work of generating the page.
  • Another option would be to make separate Binary Search Tree Checker pages for every language. When you request the page in Python 3.6, we grab the Python 3.6 template we made earlier and send it back. This is an ahead-of-time approach, since we generate complete pages before you send a request.

On Interview Cake, we take an ahead-of-time approach to generating pages in different languages. This helps make each page load quickly, since we're processing our content once instead of every time someone visits a page.

. . .