关键词:热更新 | 热重载 | 定时更新 | 即时更新 | 缓存 | functools | cachetools | LRU | TTL

假设应用需要加载一个配置文件config.txt,一般的做法类似于:

with open('config.txt') as f:

parameters = f.read()

接下来parameters中存储的数据就可以被其他代码使用,但是这样写的话程序每次启动后,数据是固定死的,无法动态地自我更新,每次要修改配置/模型只能重启整个应用。

本文中热更新的意思是在应用运行时内,从外部(如文件、数据库、REST API)中获得数据并更新应用内的Python对象。应用场景一般是应用作为服务(有对外的API),需要在不重启的前提下更新自己的配置参数或者算法模型。

热更新可以分为两种:定时更新(periodic update)和即时更新(on-call update),前者周期性地、主动地执行更新,后者则是被动地等待,直到接收到某种来自应用外部的信号才会执行更新。本文将通过内存缓存(Memory Cache)和装饰器(Decorator)技术来实现两种热更新。

内存缓存

先来说明一下内存缓存。缓存中的数据一般以键值对(key-value pair)的形式存在,value中放数据本身,key中放数据的某种描述名。缓存的容量决定了其最大可容纳的数据条数,当容量已满时再向缓存中存入新的数据,缓存就会采取开始清理行为:清除掉已存的部分数据,从而为新数据腾地方。清理的策略(具体如何清理数据)有很多种,决定了缓存的不同类型。

Python中缓存常被写成装饰器的形式,缓存数据的key里放的是被装饰原函数的参数值组合(key的生成方法可以不同,后面还会提到),value里放的则是原函数的返回值。这样当函数被调用时,程序会先去缓存数据里找是不是已经有相同的参数值,如果有就直接返回已缓存的返回值,不重复进行原函数内的计算。

注意缓存的使用有一个隐含前提:函数本身是无状态的。假如函数内引用了全局变量,或者存在闭包,那同样的参数值不一定必然计算出相同的返回值。这样缓存的返回值和实际期望的返回值就不一定一致了。

定时热更新

定时更新的实现使用了来源于第三方库cachetools的TTLCache,TTL(Time-to-Live)指存在时长策略。这种缓存为每一条存入的数据记录其存在的时长,当开始清理行为时,所有存在超过某个设定时长的数据,都会被清除掉,如果没有超时数据,缓存将会换用LRU策略(下一部分会提到)进行清理。

当我们将TTL缓存的容量设为1时、且用于加载数据的原函数参数不变的情况下,逻辑就变成了定时更新:

未超过时长:缓存保留,每次调用都使用缓存数据

超过时长,缓存清空(只有一条数据),程序重新计算(在这里即重新加载数据)

示例代码如下(运行需要安装cachetools,并在文首链接里下载完整的项目):

import time

import cachetools

from utils import change_conf_file

ROTATE = 5

@cachetools.cached(cachetools.TTLCache(1, ROTATE))

def reload():

print('Cache cleared, reloading config...')

with open('config.txt') as f:

parameters = f.read()

return parameters

class Model():

def log(self):

self.model = reload()

print(self.model)

if __name__ == '__main__':

# Reload automatically every [ROTATE] seconds

model = Model()

while True:

time.sleep(2)

change_conf_file() # change data

model.log()

即时热更新

即时更新的实现使用了来源于Python内置库functools的lru_cache,LRU(Least Recently Used)指最少使用策略。这种缓存为每一条存入的数据记录其被使用的次数,当缓存开始清理行为时,它会将使用次数最少的数据清除。

当我们将LRU缓存的容量设为1、且用于加载数据的原函数参数不变的情况下,原函数只有在第一次被调用时才会发生计算,之后调用都会直接返回缓存中的数据,到这里与一般的读取效果上并无区别。当我们需要热更新数据的时候,只需要主动清空缓存。如下例中Getter.getModel.cache_clear()。其中Getter.getModel是装饰后的函数,其中带有用于清理缓存的函数cache_clear()。有了这个扳机,我们只需要额外开发一个API(比如REST下的GET)来触发它,这样通过外部即时call API就可以进行热更新了。

示例代码如下(运行需要安装cachetools,并在文首链接里下载完整的项目):

import time

from functools import lru_cache

from utils import change_conf_file

class Getter:

@staticmethod

@lru_cache(1)

def getModel():

with open('config.txt') as f:

model = f.read()

return model

class Model():

def log(self):

self.model = Getter.getModel()

print(self.model)

if __name__ == '__main__':

# Reload only when cache_clear() is called

model = Model()

while True:

model.log()

time.sleep(2)

change_conf_file() # change data

Getter.getModel.cache_clear()

print('Cache cleared, reloading config...')

model.log()

这里补充一个细节,上面的示例中被缓存装饰器装饰的原函数getModel是一个无参数的函数,这种情况下lru_cache是如何运作的呢?lru_cache的实现中使用函数functools._make_key来生成缓存的key。在Python中,当原函数无参数时,默认参数args可认为是空元组(),可选参数可认为是空字典{},在这种情况下生成的key将会是空列表[](注意列表是不可hash的,不可直接作为字典的key,functools里的实际数据结构较为复杂,这里没有深入)。上一部分提到的第三方库cachetools实现了类似的方法keys.typedkey,两者生成的key存在区别,但是结合其他方法,行为在大部分情况是一样的,包括本文中的无参数函数情况。

import time

from functools import _make_key

from cachetools.keys import typedkey

if __name__ == '__main__':

print(_make_key((), {}, False)) # []

print(typedkey((), {}, False)) # ((), {}, , )

待探索的扩展问题

多线程情况:本文的热更新方法均基于缓存,而由于缓存涉及到读写操作,在多线程环境下我们需要考虑其正确性。functools.lru_cache和cachetools.TTLCache里均有使用到锁的机制,再考虑到Python的GIL锁,本文所述的热更新在线程安全上应该算是有保障的,但目前未经试验无法完全下断言。

import:假如我们在一个模块(module)里更新model,而另一个模块import这个model,那么当原模块的model热更新后,import得到的model并不会更新,这种行为可能与Python自身的module cache有关,如何实现所有module的热更新是一个有待探索的问题。

吐槽:这篇写得我浑身无力啊,本来觉得很简单,就平时用的小东西拿来拎拎清,没想到越拎越深…很多时候我们很happy是因为我们站在冰山的最上面,不用面对水下的魔鬼细节…作为搞技术的,我们还是不能光看脸,也要多盯裆(≖_≖)✧

python可以实现的功能_Python功能点实现:数据热更新相关推荐

  1. python热更新原理_Python功能点实现:数据热更新

    关键词:热更新 | 热重载 | 定时更新 | 即时更新 | 缓存 | functools | cachetools | LRU | TTL 假设应用需要加载一个配置文件config.txt,一般的做法 ...

  2. python读取word指定内容_python解析html提取数据,并生成word文档实例解析

    简介 今天试着用ptyhon做了一个抓取网页内容,并生成word文档的功能,功能很简单,做一下记录以备以后用到. 生成word用到了第三方组件python-docx,所以先进行第三方组件的安装.由于w ...

  3. python表格多列合并_python 合并excel表格数据-如何用python从excel中同时提取两个列的数据,并生成dict(用xlrd)...

    用Python导出工程文件两个子页里的数据成为两个excel表格,但我想把它合并成个一个excel表格的两个sheet 可以采用一些操作Excel块去实现,比如xlrd.xlwt.openpyxl.x ...

  4. python中df是什么_python数据分析之pandas数据选取:df[] df.loc[] df.iloc[] df.ix[] df.at[] df.iat[]...

    1 引言 Pandas是作为Python数据分析著名的工具包,提供了多种数据选取的方法,方便实用.本文主要介绍Pandas的几种数据选取的方法. Pandas中,数据主要保存为Dataframe和Se ...

  5. python动态图形_利用matplotlib实现根据实时数据动态更新图形

    我就废话不多说了,直接上代码吧! from time import sleep from threading importThread import numpy as np import matplo ...

  6. python 当前时间的前一天_Python与Stata的数据交互

    Python与Stata的数据交互 最近拿到了Stata的船新版本--Stata16,就迫不及待地玩了两天.总的来说,Stata16不论在UI上,还是在功能上,都比之前的版本进步了许多. 特别值得一说 ...

  7. python的前端和后端_python前端和后端数据交互,tornado框架入门,初学小试牛刀!...

    Python前端和后端是如何交互的,怎么用tornado框架快速搭建前端和后端数据交互? 前端与后端的数据交互,最常用的就是GET.POST,比较常用的用法是:提交表单数据到后端,后端返回json 前 ...

  8. python出现typeerror原因是_Python 文件添加列表数据后TypeError原因

    # -*- coding: utf-8 -*- #打开文件,将文件读入字符串 col='' f=open('pride.txt') text=f.read() cols=text.split() f2 ...

  9. python文本数据转换数值矩阵_python numpy矩阵的数据类型转换

    在python中,numpy矩阵的数据类型转换需要调用astype(),直接修改dtype是无效的.调用astype返回数据类型修改后的矩阵,但是源数据的类型不会变,需要再对源数据的赋值进行操作才可以 ...

最新文章

  1. 阅读《Android 从入门到精通》(29)——四大布局
  2. 数据分析软件python 对电脑的要求-用于数据分析的BI工具还是python?
  3. 智能电视可以安装鸿蒙操作系统吗,华为鸿蒙系统竟然支持安装第三方软件了?这再也不鸿蒙了...
  4. nth-child(n)和nth-of-type(n)
  5. [SCOI2009]生日礼物 单调性尺取法
  6. 地图自定义图标_如何在H5里添加地图导航?这份教程请收藏!
  7. java表单重复提交_JavaWeb防止表单重复提交(转载)
  8. oracle当查询没有输出返回0,ORACLE技术问题专家问答五则
  9. 巨划算|¥9.9拼12节美国外教课程,让你家娃像美国孩子一样学习英语!
  10. 主流数据库之MySQL函数和MySQL数据操作基础知识及示例
  11. 牛客网优惠码-直通BAT面试算法精品课购买
  12. cocos2dx3.0关于实现椭圆运动
  13. 定级阿里P7,300道Java面试题帮你全副武装
  14. C# 博思得 POSTEK 打印机 打码机 SDK 二次开发 指令打印
  15. handlebars.js_Handlebars.js入门指南
  16. 京浜光电IPO被终止:曾拟募资7.1亿 实控人已改为日本籍
  17. 计算机表格单元格合并,excel表格数据拆分和合并单元格-excel中如何将已经合并的单元格拆分,并将该单元格......
  18. 【Python】最全中文停用词表整理(1893个)()
  19. hcna网络技术学习指南_网络工程与弱电工程师有什么区别?这些你都会吗
  20. JavaScript WebGL 基础概念

热门文章

  1. vue在移动端出现的问题以及解决方式
  2. 身为程序员月薪还不到50k?你们好菜,我已经拿着阿里成长笔记实现财富自由了
  3. 拉格朗日乘数法和KKT条件的直观解释
  4. 7-5 先序序列+中序序列建立二叉树
  5. 论文阅读——“推荐系统”
  6. GaussDB 如何启动和关闭数据库的归档模式
  7. 使用main方法启动spring程序
  8. 无线Mesh网络相比于传统WLAN的优势有哪些?
  9. 【日拱一卒行而不辍20220926】自制操作系统
  10. 奥迪q5计算机控制显示,奥迪q5仪表盘功能图解,奥迪q5仪表盘怎么切换