上篇主要讲述了我们在平时iOS开发中常见的一些缓存及其区别,虽然这已经满足了绝大多数的场景,但是当我们遇到特殊场景的时候,又该如何呢。
缓存策略
一般来说,客户端使用LRU的缓存策略就已经足够,但是在特定场合就不是那么适用了。比如淘宝每秒百万级别的查询,如果使用LRU,那么可能有些热门商品就会被清理出缓存,从而得不偿失了。
- First In First Out (FIFO)
- Last In First Out (LIFO)
- Least Recently Used (LRU)
- Time aware Least Recently Used (TLRU)
拥有过期时间的LRU,常见的比如http缓存 - Most Recently Used (MRU)
- Random Replacement (RR)
- Segmented LRU (SLRU)
- Least-Frequently Used (LFU)
- Least Frequent Recently Used (LFRU)
- LFU with Dynamic Aging (LFUDA)
如果真的有如此特殊的场景,就需要我们去选择最优的策略来保证缓存的命中率了。
memory map
其中很多方案都提到了内存映射的技术。
内存映射会少去很多的解析编码、内存拷贝操作,所以性能上会优于普通的文件读写。
但是内存映射本身就存在一些缺陷,比如32/64操作系统的兼容性,大端小端的兼容性,字节对齐问题。所以并不是任何情况下都适合使用内存映射。如果需要保证兼容性,则需要在设计的时候就要考虑到这样的问题。
搜索优化
作为数据存储最频繁的当然是查询功能,那么如何保证查询的性能呢,那么就涉及到索引了。
操作系统本身的文件系统就带有B/B+数所做的索引,所以我们在目录下查找一个文件其实是很快的,就算这个文件夹下内容非常的多。所以一般情况下我们并不需要为文件系统做额外的索引优化。
如果是内存中的缓存,那么使用hash表是最通用的一种方式了。如果是数组则要考虑好承载能力了,少量的数据可能没有问题,当数量到达一定程度后就会暴露出来。这时候可以使用自平衡二叉树、B树、跳跃链表等来做优化了。
sqlite是我们使用最多的一种数据存储方式,提升sqlite搜索速度的方式就是对某列增加索引,具体需要根据具体情况来分析。默认的sqlite索引是B树,也可以配置为R树索引,在坐标数据库表可能会表现更优秀。
存储格式
数据的存储格式也是非常关键的一个部分。
像UserDefault这种全量更新的方式,在单一数据变化的时候就需要全部重新序列化并且全部保存,所以如果拥有大量数据或者数据非常庞大的时候,就会变得效率低下。
像ImageCache这种按照单文件保存,如果是小数据,每次都需要去读磁盘,反而效率会降低。由于磁盘的读取和写入并不是单字节的,都是按块读写是最有效率的,所以多个小数据可以一次性读取和写入。
如果是像sqlite那样按照chunk来局部更新文件,则需要非常小心的处理每个数据存储模块,同时也要非常小心处理多线程的问题。另外也需要添加索引来确保效率。
如果是随机读为主的情况下,sqlite能够完成这个任务,但是如果是以写为主,那么sqlite就可能出现性能问题(虽然按照移动客户端来说不太可能有这么大的写的需求)。
最后
如何去选择缓存和存储方案,还是需要根据实际情况,通常一个通用的方案已经足够,但是在某些特殊场景还是需要我们去自己设计这一套方案。
网友评论