Tornado热重载机制下使用lru_cache一个隐藏的坑点

经常用lru_cache来加速一些重复耗时的func, 今天栽了个坑: func的缓存在服务热重载后并没有被释放掉, 导致重跑这个方法的时候总是返回旧的数据, 放代码解释:

1
2
3
@lru_cache()
def parse_file(path):
    pass

parse_file接收一个文件路径, 对给定文件做了若干处理, 正常情况是没有问题的, 但是如果文件内容发生了变化, 本例实际上是因为要重跑某些process, 连带着这个文件内容是有更新的, 但是path不变, 在热重载的时候, 全局缓存并没有清掉, 导致每次调用方法返回的还是旧缓存数据

关于 Tornado 的热重载, 我在这里有过介绍: init_process

问题搞清楚, 解决起来就很简单, 重载的时候清一波就完事

  • 定义一个清缓存的方法
1
2
3
4
5
def clear_caches():
    # All objects cleared
    for obj in (i for i in gc.get_objects() if isinstance(i, functools._lru_cache_wrapper)):
        obj.cache_clear()
    gc.collect()
  • 热重载前清掉缓存
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
class TornadoWorker(Worker):
    ......
    def init_process(self):
        # IOLoop cannot survive a fork or be shared across processes
        # in any way. When multiple processes are being used, each process
        # should create its own IOLoop. We should clear current IOLoop
        # if exists before os.fork.
        IOLoop.clear_current()
        clear_caches()
        # You can do something like release db conn/clean fp or else.
        super().init_process()

然后, 整个世界清净了~

# NOTE: I am not responsible for any expired content.
create@2021-11-09T11:02:12+08:00
update@2021-11-09T11:03:56+08:00
comment@https://github.com/ferstar/blog/issues/48
加载评论