Beginner
Beginner

Reputation: 147

Cache in python

Recently, I tried some code about cache. I have 2 codes, 1st with using dictionary. second with using cache library. I dont understand why the time running is so different. I thought the second which used the cache library works the same as the first.

First: import time import datetime

class new():
    def __init__(self):
        self.cache = {}

    def get_candy_price(self, candy_id):
        # let's use a sleep to simulate the time your function spends trying to connect to
        # the web service, 5 seconds will be enough.
        time.sleep(5)
        if candy_id % 2 not in self.cache:
            if candy_id % 2 == 0:
                self.cache[candy_id % 2] = 1.5
            else:
                self.cache[candy_id % 2] = 1

        # let's pretend that the price returned by the web service is $1 for candies with a
        # odd candy_id and $1,5 for candies with a even candy_id

        return (datetime.datetime.now().strftime("%c"), self.cache[candy_id % 2])


# now, let's simulate 20 customers in your show.
# They are asking for candy with id 2 and candy with id 3...
for i in range(0,20):
    n = new()
    print(n.get_candy_price(2))
    print(n.get_candy_price(3))

Since everyone wants output:

Output:

('Thu Oct 25 16:14:27 2018', 1.5)
('Thu Oct 25 16:14:32 2018', 1)
('Thu Oct 25 16:14:37 2018', 1.5)
('Thu Oct 25 16:14:42 2018', 1)
('Thu Oct 25 16:14:47 2018', 1.5)
('Thu Oct 25 16:14:52 2018', 1)
('Thu Oct 25 16:14:57 2018', 1.5)
('Thu Oct 25 16:15:02 2018', 1)
('Thu Oct 25 16:15:07 2018', 1.5)
('Thu Oct 25 16:15:12 2018', 1)
('Thu Oct 25 16:15:17 2018', 1.5)
('Thu Oct 25 16:15:22 2018', 1)
('Thu Oct 25 16:15:27 2018', 1.5)
('Thu Oct 25 16:15:32 2018', 1)
('Thu Oct 25 16:15:37 2018', 1.5)
('Thu Oct 25 16:15:42 2018', 1)
('Thu Oct 25 16:15:47 2018', 1.5)
('Thu Oct 25 16:15:52 2018', 1)
('Thu Oct 25 16:15:57 2018', 1.5)
('Thu Oct 25 16:16:02 2018', 1)
('Thu Oct 25 16:16:07 2018', 1.5)
('Thu Oct 25 16:16:12 2018', 1)
('Thu Oct 25 16:16:17 2018', 1.5)
('Thu Oct 25 16:16:22 2018', 1)
('Thu Oct 25 16:16:27 2018', 1.5)
('Thu Oct 25 16:16:32 2018', 1)
('Thu Oct 25 16:16:37 2018', 1.5)
('Thu Oct 25 16:16:42 2018', 1)
('Thu Oct 25 16:16:47 2018', 1.5)
('Thu Oct 25 16:16:52 2018', 1)
('Thu Oct 25 16:16:57 2018', 1.5)
('Thu Oct 25 16:17:02 2018', 1)
('Thu Oct 25 16:17:07 2018', 1.5)
('Thu Oct 25 16:17:12 2018', 1)
('Thu Oct 25 16:17:17 2018', 1.5)
('Thu Oct 25 16:17:22 2018', 1)
('Thu Oct 25 16:17:27 2018', 1.5)
('Thu Oct 25 16:17:32 2018', 1)
('Thu Oct 25 16:17:37 2018', 1.5)
('Thu Oct 25 16:17:42 2018', 1)

real    3m20.145s
user    0m0.031s
sys     0m0.016s

Second:

import time
import datetime

from cachetools import cached, TTLCache  # 1 - let's import the "cached" decorator and the "TTLCache" object from cachetools
cache = TTLCache(maxsize=100, ttl=300)  # 2 - let's create the cache object.

@cached(cache)
def get_candy_price(candy_id):
    # let's use a sleep to simulate the time your function spends trying to connect to
    # the web service, 5 seconds will be enough.
    time.sleep(5)

    # let's pretend that the price returned by the web service is $1 for candies with a
    # odd candy_id and $1,5 for candies with a even candy_id

    price = 1.5 if candy_id % 2 == 0 else 1

    return (datetime.datetime.now().strftime("%c"), price)


# now, let's simulate 20 customers in your show.
# They are asking for candy with id 2 and candy with id 3...
for i in range(0,20):
    print(get_candy_price(2))
    print(get_candy_price(3))

Output:

('Thu Oct 25 16:32:28 2018', 1.5)
('Thu Oct 25 16:32:33 2018', 1)
('Thu Oct 25 16:32:28 2018', 1.5)
('Thu Oct 25 16:32:33 2018', 1)
('Thu Oct 25 16:32:28 2018', 1.5)
('Thu Oct 25 16:32:33 2018', 1)
('Thu Oct 25 16:32:28 2018', 1.5)
('Thu Oct 25 16:32:33 2018', 1)
('Thu Oct 25 16:32:28 2018', 1.5)
('Thu Oct 25 16:32:33 2018', 1)
('Thu Oct 25 16:32:28 2018', 1.5)
('Thu Oct 25 16:32:33 2018', 1)
('Thu Oct 25 16:32:28 2018', 1.5)
('Thu Oct 25 16:32:33 2018', 1)
('Thu Oct 25 16:32:28 2018', 1.5)
('Thu Oct 25 16:32:33 2018', 1)
('Thu Oct 25 16:32:28 2018', 1.5)
('Thu Oct 25 16:32:33 2018', 1)
('Thu Oct 25 16:32:28 2018', 1.5)
('Thu Oct 25 16:32:33 2018', 1)
('Thu Oct 25 16:32:28 2018', 1.5)
('Thu Oct 25 16:32:33 2018', 1)
('Thu Oct 25 16:32:28 2018', 1.5)
('Thu Oct 25 16:32:33 2018', 1)
('Thu Oct 25 16:32:28 2018', 1.5)
('Thu Oct 25 16:32:33 2018', 1)
('Thu Oct 25 16:32:28 2018', 1.5)
('Thu Oct 25 16:32:33 2018', 1)
('Thu Oct 25 16:32:28 2018', 1.5)
('Thu Oct 25 16:32:33 2018', 1)
('Thu Oct 25 16:32:28 2018', 1.5)
('Thu Oct 25 16:32:33 2018', 1)
('Thu Oct 25 16:32:28 2018', 1.5)
('Thu Oct 25 16:32:33 2018', 1)
('Thu Oct 25 16:32:28 2018', 1.5)
('Thu Oct 25 16:32:33 2018', 1)
('Thu Oct 25 16:32:28 2018', 1.5)
('Thu Oct 25 16:32:33 2018', 1)
('Thu Oct 25 16:32:28 2018', 1.5)
('Thu Oct 25 16:32:33 2018', 1)

real    0m10.121s
user    0m0.031s
sys     0m0.016s

Can anyone show me the example of codes in a more understanding way for cache in second? For example, is it possible to change it to something more easy to see how the library runs for cache such like in first? The difference is about 3minutes differ.

My goal:

Is to understand the cache in python and so I tried to implement two different ways; one with library and another without. So cache with library is actually the same as making our own dictionary? So does it mean by cache it means we make a dictionary which act as look-up table?

Upvotes: 0

Views: 1929

Answers (2)

Sujay Kumar
Sujay Kumar

Reputation: 568

You can always play with the code dude,

Your first example is poor to understand the cache mechanism, you are making

Your cache element is going to be formed again & again, as n = new() is re-initializing itself. Loosing all the cache. That is why it’s taking too long. Make it like,

 n = new()
 for i in range(0,20):
    print(n.get_candy_price(2))
    print(n.get_candy_price(3))

Another thing,

    # let's use a sleep to simulate the time your function spends trying to connect to
    # the web service, 5 seconds will be enough.
    time.sleep(5)

You want to cache, Right? Then why this web call is getting called every time. This should always be called only when the answer is not in cache already, I am redefining your get_candy_price function,

def get_candy_price(self, candy_id):
    # for observing the results
    print (self.cache, candy_id)
    if candy_id % 2 not in self.cache:

        # as this wasn't already in cache
        # let's use a sleep to simulate the time your function spends trying to connect to
        # the web service, 1 seconds will be enough.
        time.sleep(5)
        if candy_id % 2 == 0:
            self.cache[candy_id % 2] = 1.5
        else:
            self.cache[candy_id % 2] = 1
    else:
        # as we already have cached it
        return self.cache[candy_id % 2]
    return (datetime.datetime.now().strftime("%c"), self.cache[candy_id % 2])

In second example, play with ttl parameter

 cache = TTLCache(maxsize=100, ttl=5)

Observe, it’s not going that fast now is it? It’s because you ttl(Time to live) parameter is caching the result for a certain amount of time. Google it for more!

Upvotes: 0

ZisIsNotZis
ZisIsNotZis

Reputation: 1740

Your first example sleep for 5 seconds no matter it has cache or not, put that line into the if, like

    if candy_id % 2 not in self.cache:
        time.sleep(5)
        if candy_id % 2 == 0:
            self.cache[candy_id % 2] = 1.5
        else:
            self.cache[candy_id % 2] = 1

Also the second example is caching the return-current-time. Therefore, the time part cannot be trusted.

Upvotes: 0

Related Questions