Skip to main content

Python decorators for store in-data memory using LRU cache

Project description

LRU Cache

PyPI - Python Version PyPI - Status PyPI Downloads

Package for tracking store in-data memory using replacement cache algorithm / LRU cache. The Priority of storing or removing the data based on Min-Max heap algorithm or basic priority queue instead using OrderedDict module that provided by Python.

Purpose

The purpose of using this package itself is at least to be able to dynamically tracking. inserting, and removing least frequently used in-data memory or in an element. Another purposes, with the use of python decorator or the method looks like, it's also possible to figure it out whether the data in the cache is full or not (it's called LRU eviction), since Min-Max heap algorithm is using O(1) complexity for basic insertion and searching, it's also possible to efficiently accessing the store in-data memory based on most frequently used method.

Usage

LRUCache only works in Python version 3.5 and above, you can install it with :

pip install lruheap

There is a little explanation regarding the use of this LRU cache. You can see at this simple configuration and explanation for using several method that provided by this package.

LRUCache(capacity=128, seconds=60*15)

Class constructor for initialize LRUCache method with maximum capacity of cache is 128 and maximum duration of cache is 15 minutes when you don't initialize at first. For example:

from lru.lrucache import LRUCache

foo = LRUCache(3)

# or you can set param argument
foo = LRUCache(capacity=3, seconds=5*15)

set()

Set an objects that wants to be cached in cache element, given the key parameters and value parameters as integer. For example:

foo.set(1, "foobar")
foo.set(2, "bar")

get()

Get the objects based on their key in cache element and access time, given the key parameters as integer. This get() method can also be used to tracking which objects are often called which will later be identified as recently used objects in a cache element, an object that is often called by this method will be placed in front of the cache element by using get_lru_element(). For example:

foo.get(1)
foo.get(1) # you can iterate for calling an object
foo.get(2)

get_dict()

Method for returned a all dictionary of an object in cache element. For example:

foo.get_dict()

get_duration()

Method for getting duration of cache, return True if the duration is exceed for expired time otherwise return False when the duration is even or below the expired time. The expired time set as 3600 seconds. For example:

# will return True if the duration
# of cache is still under the
# expired time
foo.get_duration()

get_lru_element()

Method for retrieved an object based on their key in cache element and the duration when accessing onto the dictionary. If the object is not called by the get() method, then objects that have short time for accessing onto dictionary will be placed in beginning of the cache element, if the object is called by the get() method, it will placed depending how many objects are called. In this case, this called as recently used. For example:

foo.get_lru_element()

get_capacity()

Get cache capacity, return True if the cache is full otherwiser return False when the cache is not full. For example:

foo.get_capacity()

get_cache()

Get cache in element based on their key, return True if the element has a key, otherwise return False when element hasn't a key. Given the key parameters as integer. For example:

foo.get_cache(1)

clear_all()

Remove all cache in element. For example:

foo.clear_all()

clear_cache_key()

Remove cache in element based on their key. Given the key as parameters for remove the cache objects. For example:

foo.clear_cache_key(1)

@lru_cache(capacity=128)

Python decorators using LRUCache classes for cache an object within a function. Default capacity is 128 if you not define it. For example:

from lru.decorators import lru_cache

@lru_cache(capacity=5)
def test_lru(x):
    print("Calling f(" + str(x) + ")")
    return x

test_lru.set(1, "foo")
test_lru.set(2, "test")
test_lru.set(3, "foos")
test_lru.set(4, "fc")
test_lru.set(5, "set")
test_lru.get_capacity()

@lru_cache_time(capacity=128, seconds=60*15)

Python decorators for LRUCache classes using expired cached time. This is an mock only, probably not ready to bump into major version, if you want to try it and there is an error or an unexpected result, please raise the issue. For example :

from lru.decorators import lru_cache_time

@lru_cache_time(capacity=5, seconds=15)
def test_lru(x):
    print("Calling f(" + str(x) + ")")
    return x

test_lru.set(1, "foo")
test_lru.set(2, "test")

The difference between set duration of cache if using decorators or not lies when we set the value of the duration cache. By using these @lru_cache_time decorators at least it will compact and dynamically clear the cache if the duration exceeds of the maximum duration (15 minutes).

Further Example

Backported with Django

For further example, hopefully this package can be backported with Python web frameworks such as Django or Flask which can be implemented and supported in the JSON field area, since the return of this LRUCache value is in the form of dictionary which is very common in JSON type. For simple usage in Django, you must setting the LRUCache in installed application within Django settings like this :

INSTALLED_APPS = [
    ...
    'lru',
    ...
]

And then you can create some function for wrapped the objects that you want to cached with JsonResponse from Django API. The results of this function will return your objects in the form of a JSON dict at your web browser :

# views.py

from django.http import JsonResponse
from lru.lrucache import LRUCache

# set the capacity of LRUCache
test = LRUCache(3)

# wrapped our object
def test_lru(request):
    test.set(1, "foo")
    test.set(2, "bar")
    return JsonResponse(test.get_dict(), safe=False)

Dont forget to passing our function method into Django urls parameters :

# urls.py

from django.urls import path
from . import views

urlpatterns = [
    path('', views.test_lru),
]

After that you can run the django server and see it in a web browser based on your endpoint url. Please remember, at the moment, each time after you wrapped the object with JsonResponse, you need to set the safe parameter to False because when you set an object with LRUCache, we don't set it to dict type, while the output from JsonResponse itself is dict type.

Backported with Flask

For simple usage in Flask probably occured by using the LRUCache decorators on top of the router flask decorator. Ensure you've already installed Flask with pip install flask and then create new file such as the following example :

# app.py

from flask import Flask
from lru.decorators import lru_cache_time

app = Flask(__name__)

@lru_cache_time(seconds=60)
@app.route("/")
def hello():
    return "Hello World!"

if __name__ == "__main__":
    app.run()

After that, you can run the Flask app with the command like python app.py and then open it in the browser according to the existing localhost. As for noted, the use of the @lru_cache_time decorators itself will set the cache capacity and duration of the cache. Since here we only return plain text / html with Hello World output, i'm assume we don't need to set the cache capacity.

Basically, in this example there's a several confusion and caveats :

  • After the cache duration that we have set exceeds the maximum limit of expired time, will the value of the function be deleted or not? cause the output is not JSON type (probably i'll given a try to using the jsonify method or make_response).
  • Secondly, whether the value it still be stored and appears in a web browser or not, if we stop the flask server.

Likewise, the use of LRUcache in Django or Flask itself is very limited at this time, because there is a contradiction that is we can't set the objects dynamically, and another obstacle is that if the object that we set is not in the dict type, we need to do the object hashing. Normally, using LRUCache at the web-environment level can be done with the following assumptions like :

  • You want to build web-based streaming services
  • You do object modeling in the database, such as creating objects for a song that is least or most recently heard.
  • You set the song object with LRUCache, so that every time you open your site, that song will appear.

Another example of using this LRU cache is that you want to display a book that is most often searched by keywords, dynamically remove an object that is not or least used, store data of users who frequently visit our site and many others.

Why using this, instead of X?

Why use object cache level instead of filtering method or get method based on API? Ideally, cache is fast. and just fast as storage, reading or accessing the data from a cache takes less time than reading the data from something else. in example if you use filtering methods, you are doing accessing and getting the object from your database. Otherwise, caching the object improves performance by keeping recent or most used data in memory locations rather we're going to use computationally object from database.

Roadmap

  • Use classes as decorators for caching the objects
  • Add expired time for caching objects
  • Add thread safe parameter
  • Scale the LRUCache capacity
  • Backported and integrated with Django request and response
  • Write unittest for LRUCache

Contributions

Since this package is still being under developed, any contributions are much welcomed and you can read on contribution page.

License

This package is licensed under the MIT License.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

lruheap-0.1.0.tar.gz (9.2 kB view hashes)

Uploaded Source

Built Distribution

lruheap-0.1.0-py3-none-any.whl (9.9 kB view hashes)

Uploaded Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page