Python高速缓存和会话库——Beaker

简介

Beaker 是一个高速缓存和会话库,用于 Web 应用和独立 Python 脚本。

Beaker 附带 WSGI 中间件,可在基于 WSGI 的 Web 应用中直接使用。

Beaker 带有缓存装饰器,可在任何 Python 应用中使用。

Beaker 最初基于Perl Cache::Cache模块,进行了大量的更新和重写。

特性:

  • 延迟加载
  • 高性能
  • 多后端
    基于文件、DBM文件、memcached、内存、Redis、MongoDB、数据库等
  • 基于Cookie会话
  • 灵活的缓存
    每个函数可以使用不同的过期时间和不同的键将数据缓存到不同的后端
  • 可扩展后端

缺点:

  • 不支持异步缓存

PS:本文偏向于缓存而非会话。




安装

pip install beaker




基本概念

Beaker 能以不同方式配置,首推使用字典,传递给 SessionMiddlewareCacheManager

缓存

使用Beaker的缓存有三种方式:

  1. 编程API(传统)
    公开名称空间并检索缓存对象,该缓存对象处理键值。
  2. 缓存装饰器(推荐)
  3. cache_region() 装饰器(更灵活)




初试

test.txt

Hello World!

方式1. 编程API

from beaker.cache import CacheManager
from beaker.util import parse_cache_config_options

# 1. 实例化CacheManager
cache_opts = {
    'cache.type': 'file',
    'cache.data_dir': '/tmp/cache/data',
    'cache.lock_dir': '/tmp/cache/lock'
}

cache = CacheManager(**parse_cache_config_options(cache_opts))


def get_data(filename):
    '''获取数据的方式'''
    print(filename)
    with open(filename) as f:
        return f.read()


def get_results():
    '''要缓存的函数'''
    data = get_data(filename)
    return data


if __name__ == '__main__':
    # 2. 通过编程API使用缓存
    temp_cache = cache.get_cache('temp', type='file', expire=10)  # 实例化一个缓存,命名空间为temp,使用文件缓存,过期时间为10s

    # 3. 创建&读取缓存
    filename = 'test.txt'
    results = temp_cache.get(key=filename, createfunc=get_results)
    print(results)

    # temp_cache.clear()  # 删除所有缓存

    # temp_cache.remove_value(key=filename)  # 删除特定缓存

效果

在这里插入图片描述

方式2. 缓存装饰器

from beaker.cache import CacheManager
from beaker.util import parse_cache_config_options

# 1. 实例化CacheManager
cache_opts = {
    'cache.type': 'file',
    'cache.data_dir': '/tmp/cache/data',
    'cache.lock_dir': '/tmp/cache/lock'
}

cache = CacheManager(**parse_cache_config_options(cache_opts))


def get_data(filename):
    '''获取数据的方式'''
    print(filename)
    with open(filename) as f:
        return f.read()


# 2. 通过装饰器使用缓存
@cache.cache('temp', type='file', expire=10)
def get_results(filename):
    '''要缓存的函数'''
    data = get_data(filename)
    return data


if __name__ == '__main__':
    # 3. 创建&读取缓存
    filename = 'test.txt'
    results = get_results(filename)
    print(results)

    # cache.invalidate(get_results, 'temp', filename, type='file')  # 删除特定缓存




测试时间

递归计算n=35的斐波那契数列

import time
from beaker.cache import CacheManager
from beaker.util import parse_cache_config_options

cache_opts = {
    'cache.type': 'file',
    'cache.data_dir': '/tmp/cache/data',
    'cache.lock_dir': '/tmp/cache/lock'
}

cache = CacheManager(**parse_cache_config_options(cache_opts))


def fib1(n):
    '''不带缓存的斐波那契数列'''
    if n < 2:
        return n
    return fib1(n - 1) + fib1(n - 2)


@cache.cache('temp', type='file', expire=60)
def fib2(n):
    '''带缓存的斐波那契数列'''
    if n < 2:
        return n
    return fib2(n - 1) + fib2(n - 2)


if __name__ == '__main__':
    beg = time.time()
    result1 = [fib1(i) for i in range(35)]
    print('{:.2f} s'.format(time.time() - beg))

    beg = time.time()
    result2 = [fib2(i) for i in range(35)]
    print('{:.2f} s'.format(time.time() - beg))

    # 5.25 s
    # 0.04 s




最大整数

import sys

print(sys.maxsize)

可作永久缓存




使用MongoDB

beaker.ext.mongodb

from beaker.cache import CacheManager
from beaker.util import parse_cache_config_options

cache_opts = {
    'cache.type': 'ext:mongodb',
    'cache.url': 'mongodb://localhost:27017/cache',  # 本机MongoDB,数据库名cache
    'cache.expire': 10  # 过期时间
}

cache = CacheManager(**parse_cache_config_options(cache_opts))


@cache.cache('fib')
def fib(n):
    if n < 2:
        return n
    return fib(n - 1) + fib(n - 2)


if __name__ == '__main__':
    result = [fib(i) for i in range(35)]
    print(result)
    # fib(1)  # 延迟清缓存

在这里插入图片描述

过期时间为10s,只要一直不运行,这些记录都会保存,即延迟加载。

过了10s后调用 fib(1),将会清除过期缓存,库中数据只剩一个新的。




删除缓存

调用 cache.invalidate(函数名, ('Cache名', *args.values()), type='file')

import time
from pathlib import Path
from beaker.cache import CacheManager
from beaker.util import parse_cache_config_options

cache_opts = {
    'cache.type': 'file',
    'cache.data_dir': Path(__file__).parent / 'cache/data',  # 当前目录
    'cache.lock_dir': Path(__file__).parent / 'cache/lock'
}

cache = CacheManager(**parse_cache_config_options(cache_opts))


@cache.cache('fun', type='file', expire=60 * 5)
def fun(a, b, c):
    time.sleep(a + b + c)
    return a + b + c


if __name__ == '__main__':
    # 1.函数参数
    args = dict(a=0.2, b=0.3, c=0.5)

    # 1.首次运行
    beg = time.time()
    fun(**args)
    print(time.time() - beg)

    # 2.再次运行
    beg = time.time()
    fun(**args)
    print(time.time() - beg)

    # 3.删除对应缓存
    cache.invalidate(fun, 'fun', *args.values(), type='file')

    # 4.重新运行
    beg = time.time()
    fun(**args)
    print(time.time() - beg)

    # 1.003999
    # 0.000999
    # 1.000999




封装

import sys
from pathlib import Path
from beaker.cache import CacheManager
from beaker.util import parse_cache_config_options

cache_opts = {
    'cache.type': 'file',
    'cache.data_dir': Path(__file__).parent / 'cache/data',  # 当前目录
    'cache.lock_dir': Path(__file__).parent / 'cache/lock'
}

cache = CacheManager(**parse_cache_config_options(cache_opts))


def delete_cache(func, args, type='file'):
    '''删除特定缓存

    :param func: 调用的函数
    :param args: 调用的具体参数
    :param type: 缓存类型
    '''
    cache.invalidate(func, func.__name__, *args.values(), type=type)


@cache.cache('fib', type='file', expire=sys.maxsize)  # 永久缓存,建议同函数名
def fib(n):
    if n < 2:
        return n
    return fib(n - 1) + fib(n - 2)


if __name__ == '__main__':
    result = [fib(i) for i in range(35)]
    print(result)




异步缓存

异步缓存如何实现? Beaker 通过 NamespaceManager 进行缓存的读、写、锁操作,保证唯一性。

如MongoDB后端,可以观察到其 _id 是根据调用的绝对路径和参数决定的,那么只要保证 _id 一致,即可实现分布式缓存。

但这样做可能丧失唯一性。

推荐阅读

  1. Python中的缓存
  2. 缓存使用过程中的五种策略总结及优缺点组合分析
  3. Asynchronous Caching with Python
  4. aiocache: Asyncio cache manager for redis, memcached and memory




参考文献

  1. Beaker Documentation
  2. Beaker GitHub
  3. WSGI接口
  4. 会话和缓存配置
  5. Asynchronous Caching with Python
  6. aiocache: Asyncio cache manager for redis, memcached and memory
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

XerCis

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值