情诗网 >心情说说 > 正文

也说说缓存的事情(一)

来源:情诗网    2021-03-01    分类:心情说说

There are only two hard things in Computer Science: cache invalidation and naming things.-- Phil Karlton

计算机科学只有两大难题:缓存失效和命名。


缓存

最近我遇到了一些棘手的问题,测试说程序特别的慢,打开一个页面要半分钟,简直不能忍受,我用了tcpdump简单一查,呃,原来是相同的sql语句一直在重复执行。我想,该加缓存了。

缓存顾名思义就是一种临时数据,让程序可以把数据随手拿来而不用踏遍万水千山去数据库或者硬盘中去取。这点是很重要的,比如,你考试前狂背了一堆东西,然后把考试应付过去了,考完试了,考试背的东西也早就say good bye了,这就是典型的缓存,并没有真正的存储起来,背书的目的只是为了方便考试。;-)

对于一个程序而言,使用缓存的目的,就是让你的程序能够快起来,能把运算过的数据全部存起来,用的时候就可以直接用了,而不是再算一遍。就拿斐波那契数列而言,程序完全可以这样写:

# python 
# fibonacci数列
def fibonacci(n):
    if n < 2: 
        return n
    return fibonacci(n - 1) + fibonacci(n - 2)

当n比较小的时候,可以很轻松的算出来,但是当n稍微大一点,这样写就不行了,得稍微添点儿东西。

# python 
# fibonacci数列 -- 改进版

fibonacci_cache = dict()  # 缓存fibonacci算过的数据

def fibonacci(n):
    if n < 2: 
        return n
    if n in fibonacci_cache:  # 如果n在fibonacci数列中,则直接返回结果
        return fibonacci_cache[n]
    else: # 如果n不在fibonacci数列中,则计算结果,并缓存,再返回
        fibonacci_cache[n] = fibonacci(n - 1) + fibonacci(n - 2) 
        return fibonacci_cache[n]

咱们分析分析这几行程序:其实就添加了一个dict,将每次fibonacci函数计算的结果缓存起来。你也可以不用dict,可以用任意的东西储存这个结果,哪怕是放在文件里面,最好是用k/v结构,如果你注意过,肯定发现了几乎所有的缓存系统都是k/v结构的,比如,cookieredis还有Tair

似乎问题就解决了,但是其中还有一个大问题,那就是斐波那契数列输入一个n,只有一种输出结果,而现实不是这样的……

理想很丰满,现实很骨感

很多时候,存到数据库的东西,或者访问一个网址,它的标签是一样的,内容却是一直在变,那么就涉及到了缓存失效的问题了。当然缓存失效是一个很大的问题,我这里只能介绍一下最简单的东西,后面我会写一篇文章专门说这个内容的。

如果你的计算结果是可变的,那么一般应该采用如下的流程,这种流程称作主动式的缓存失效:

主动缓存失效

流程是这样的,你有两个线程(或者两个进程…),一个线程是用来查询的,一个线程是用来计算的,那么那个计算的线程某些时候计算出一个结果,发现这个结果在缓存中没有存在,或者存在的不是最新的值,那么就将其更新。另外一个查询的线程直接查,如果缓存中有,则直接用缓存中的内容,如果没有,则计算、放入缓存,并返回结果。

当然,有主动式的缓存失效就有被动式的缓存失效。当你计算了一个结果,连同时间一起放入缓存中,然后你定一个规则,只取1分钟内缓存的内容,超过1分钟的全部失效,重新计算,那么流程就会变成这样:

被动缓存失效

这种被动式的缓存其应用场景就留给看官们自己想了:)

我这里提到的更多的是一种基本的思想,当然你把它加到你的程序里面,可以直接的提升你的程序的性能!

这里有一段我写的python的缓存函数调用的装饰器,如果有需要,可以直接用!

ps. 下一篇我会说说缓存的应用

热门文章