函数输入输出缓存装饰器@lru_cache

-- TOC --

functools.lru_cache是一个函数输入输出缓存装饰器,lru关键字说明了算法,Least Recently Used,这个算法被用在很多地方,比如OS做虚拟内存swap的时候。

LRU算法的思想:将最近最少使用到的区域,进行某个动作,比如置换到硬盘,或者从缓存中删除以释放缓存空间。

functools.lru_cache装饰函数后,会将函数的输入和输出以哈希表的形式进行缓存,如果在下次调用此函数时,出现了相同的输入,那么相同的输出就可直接从缓存中提取,函数体本身无需再次执行。用一点内存,加快了解释执行的速度。(速度不够,内存来凑)

Arguments to the cached function must be hashable.

lru_cache(maxsize=128, typed=False)
    Least-recently-used cache decorator.

    If *maxsize* is set to None, the LRU features are disabled and the cache
    can grow without bound.

    If *typed* is True, arguments of different types will be cached separately.
    For example, f(3.0) and f(3) will be treated as distinct calls with
    distinct results.

    Arguments to the cached function must be hashable.

    View the cache statistics named tuple (hits, misses, maxsize, currsize)
    with f.cache_info().  Clear the cache and statistics with f.cache_clear().
    Access the underlying function with f.__wrapped__.

    See:  http://en.wikipedia.org/wiki/Cache_replacement_policies#Least_recently_used_(LRU)

maxsize默认是128,缓存函数输入输出pair的数量,如果设置为None,grow without bound,即缓存会无限增大,慎用!

typed如果为True,不同类型的入参将被视为不同的输入进行缓存。

以上两个参数的设置,要根据具体函数而定。而能够被lru_cache装饰的函数,也需要满足一定的条件,否则就没有效果,或者起反作用。比如:函数的输入输出是一个相对固定较小的集合,或者有一个子集会高频的出现。

下面是一点测试代码:

>>> import functools
>>> @functools.lru_cache
... def test(a,b):
...     print('i am in test')
...     return a+b
...
>>> test(1,1)
i am in test
2
>>> test(1,1)
2
>>> test(2,2)
i am in test
4
>>> test(2,2)
4
>>> test.cache_info()
CacheInfo(hits=2, misses=2, maxsize=128, currsize=2)
>>> test.cache_clear()
>>> test(1,1)
i am in test
2
>>> test(2,2)
i am in test
4
>>> test.cache_info()
CacheInfo(hits=0, misses=2, maxsize=128, currsize=2)

被functools.lru_cache装饰后的函数,多了两个可调用的接口,分别是cache_info和cache_clear,分别用来查看函数cache的使用状态,以及清空cache。

这个lru_cache函数装饰器是可以起到一点执行加速的作用。我觉得这个思路也可以用在C/C++代码中。

本文链接:https://cs.pynote.net/sf/python/202204062/

-- EOF --

-- MORE --