聊聊Yii2和ThinkPHP5的文件缓存 

admin  

翻一翻Yii2和ThinkPHP5的源码,看看它们的文件缓存。看看这些使用广泛的框架如何设计一个缓存操作类。

Yii2和ThinkPHP5缓存操作提供的公共方法对比

Yii2缓存提供的方法
  • get 获取对应$key缓存,不存在或过期返回false
  • set 设置缓存数据
  • exists 判断缓存是否存在
  • mset multiSet 方法别名,用于批量设置缓存
  • mget multiGet 方法别名,用于批量获取缓存
  • add 添加缓存 返回true,如果缓存已经存在则不做操作返回false
  • madd 批量添加多个,返回成功插入的缓存键名数组
  • delete 删除缓存
  • flush 清空缓存所有数据
  • offsetExists exists别名
  • offsetGet get别名
  • offsetSet set别名
  • offsetUnset delete别名
  • getOrSet 获取缓存,如果不存在则根据传入的回调函数设置缓存

ThinkPHP5缓存提供的方法

  • get 获取缓存
  • set 设置缓存
  • inc 缓存数据自增
  • dec 缓存数据自减
  • rm 删除缓存
  • clear 根据tag 删除缓存
  • pull 读取缓存并删除缓存
  • remember 读取缓存,缓存不存在则根据传入的函数设置缓存的值
  • tag 缓存分组加标签
  • has 判断缓存是否存在

Yii2 和ThinkPHP5 缓存操作对比

  • 读写操作 ThinkPHP5 读写缓存文件都是通过file_get_contents和file_put_contents操作文件,且不加任何锁。因此在极端情况下,有可能会出现读取文件头不对尾的情况。如果遇到多个请求同时写缓存,会涉及到并发问题。Yii2读取缓存加共享锁LOCK_SH,写缓存加排它锁LOCK_EX保证读写数据完整。

  • ThinkPHP5 虽然实现了自增自减方法,但是内部实现实际上是先读取后设置,并且中间没有锁操作,所以在多个请求同时对数据进行自增自减的情况数据会不正确。如果要实现原子操作的自增自减,两个框架都需要开发者自己去实现。

  • Yii2缓存过期方式通过修改文件的更改时间记录过期时间。ThinkPHP5 则是在缓存文件中插入过期时间数据,根据文件最后修改时间以及过期时间确定缓存是否过期。

  • Yii2缓存有gc机制,在每次写入缓存的时候会以一定的概率删除过期缓存文件。ThinkPHP5 则是在读取缓存的时候,如果缓存过期则删除。如果缓存保存的是多层级的文件夹,Yii2会删除缓存文件夹,但是ThinkPHP5 不会删除。因此ThinkPHP5 需要开发者编写额外的脚本去定期删除缓存文件,避免空间占用。

  • 两种框架都支持缓存可序列化数据。Yii2缓存操作支持自定义数据序列化方法,默认使用serialize方式。 ThinkPHP5 只能是开发者在每次调用的时候用自定义的方法序列化在存入缓存或者使用默认serialize序列化。

  • Yii2缓存可以设置依赖,当依赖的数据变更,缓存依赖器会将相关的缓存设置成过期状态。ThinkPHP5 没有。

文件缓存中一些其他东西

  • 文件锁

LOCK_SH 共享锁(读文件),LOCK_EX 排它锁(写文件),LOCK_UN 释放锁,LOCK_NB 锁定不阻塞

写文件先执行写锁,其他进程不能读文件,必须等写锁释放。如果读文件加了LOCK_NB标志,则读文件不阻塞,直接读取失败!

读文件先执行读锁,其他进程可读。写入文件必须等读锁释放。如果写文件加了LOCK_NB标志,则写文件不阻塞,直接失败

  • 文件状态缓存

PHP会缓存对文件状态信息的检查结果。如果在一个脚本中多次检查同一个文件,只在最初会读取信息,其他都是从缓存中获取。受影响的函数有:stat() lstat() file_exists() is_writable() is_readable() is_executable() is_file() is_dir() is_link() filectime() fileatime() filemtime() fileinode() filegroup() fileowner() filesize() filetype() fileperms()因此如果文件被操作过或者不需要缓存文件状态,则需要清除文件状态缓存,使用clearstatcache清除文件状态缓存