美文网首页
Python 爬虫进阶篇——diskcahce缓存(二)

Python 爬虫进阶篇——diskcahce缓存(二)

作者: 那个百分十先生 | 来源:发表于2021-09-02 22:46 被阅读0次

    上一篇文章跟大家介绍了一下diskcache的基础用法,本次推文带大家了解一下关于diskcache更深入的东西。

    关于diskcache

    diskcache缓存对象管理是基于SQLite数据库,它是一个轻量级的基于磁盘的数据库,该数据库不需要单独的服务器进程,并允许使用SQL查询。大家如果注意到,上篇推文中的源码截图上有一些sql的语句。

    FanoutCache 分片

    diskcache可使用diskcache.FanoutCache 自动分片基础数据库。分片是对数据进行水平分区。可用于减少阻塞写入。尽管读和写不会互相阻碍,但写入会阻碍其他写入。分片默认值为8。

    代码如下:

    from diskcache import FanoutCache
    
    cache=FanoutCache(r"D:\python\cachedb\diskcahce_2",shards=4,timeout=1)
    cache.set("python","python知识学堂欢迎你!")
    print(cache.get("python"))
    

    diskcache_2文件件情况,如下:


    上面的示例在一个diskcache_2文件夹中创建一个具有四个分片和一秒超时的缓存。如果操作花费的时间超过一秒,它们将尝试中止操作。

    那么每一个分片的大小是多少呢?分片的大小都是平均分配的,占总空间的四分之一。diskcache的默认大小为1GB。

    Deque双端队列

    diakcache提供了一个collections.deque兼容的双端队列diskcache.Deque。双端队列是堆栈和队列的一般化,可以在前后都可以进行快速访问和编辑,可持久化,比较便捷。

    如下示例:

    from diskcache import Deque
    
    deque=Deque(range(5,10))
    print(str(deque.popleft())+"/"+str(deque.pop()))
    
    deque.appendleft(4)
    deque.append(10)
    deque.extendleft([1,2,3])
    deque.extend([11,12,13])
    print(str(deque.popleft())+"/"+str(deque.pop()))
    

    运行结果:

    Popleft 获取队列最前面的一个元素,pop获取末尾的一个元素;

    Appendleft 在队列最开始添加一个元素,append 在末尾添加一个元素;

    Extendleft 在队列最开始添加一个数组,extend在末尾添加一个数组;

    那么deque的存储的位置在哪里?可以使用下面的命令查看队列存储的位置:

    deque.directory
    

    包括cache也是一个可以使用directory属性查看默认存储的位置;

    那么如何指定directory呢?Deque的第二个参数指定存储位置,第一个参数为队列的初始值。或者可以直接指定参数名称,如下:

    deque=Deque([],r"D:\python\cachedb\diskcahce_3")
    deque=Deque(directory=r"D:\python\cachedb\diskcahce_3")
    

    Index

    Index 类似于dict(字典),可持久化,使用也比较便捷。如下示例:

    from diskcache import Index
    
    index=Index(r"D:\python\cachedb\diskcahce_5")
    # index["python"]="python知识学堂欢迎你!"
    # index["python1"]="python知识学堂非常欢迎你!"
    # index["python2"]="python知识学堂非常非常欢迎你!"
    print(index.popitem())
    

    popitem表示获取最后一个键对值,并且删除,结果如下:


    peekitem() 可传递last 参数是否获取最后一个,不会删除原始值;

    setdefault(key,default) 可以给指定的key值设置默认值,在查找时可以预先设置一个默认值,防止key值不存在而抛出异常。

    keys()与values()可以查找所有Index中的key值与value值,然而没有提供判断key值是否存在的方法,但是可以使用setdefault的方法自行封装。

    Lock

    还记得上篇文章中提到的Lock锁么?先看一下源码:

    可以看到这里的锁用的就是cache的add方法的特性,源码中也给出了使用的方式:

    from diskcache import Lock
    
    cache=Cache(r"D:\python\cachedb\diskcahce_1")
    lock=Lock(cache,"lock_key")
    
    #锁开始
    lock.acquire()
    
    #业务处理 TODO
    
    #锁释放
    lock.release()
    

    从源码上看有一个while 死循环,直到add成功时才会被释放,这里处理的方式不是很好,可能会造成死锁,所以一般情况下,都会添加一个过期的时间,如下:

    lock=Lock(cache,"lock_key",expire=5)
    

    RLock

    还有一种RLock锁,与Lock锁的区别是RLock允许在同一线程中被多次acquire。而Lock却不允许这种情况。如下:

    cache=Cache(r"D:\python\cachedb\diskcahce_1")
    
    rLock=RLock(cache,"rlock_key",expire=5)
    rLock.acquire()
    rLock.acquire()
    
    rLock.release()
    rLock.release()
    print("执行成功")
    

    结果是执行成功。

    看一下源码:

    从源码中可以看出,判断锁的条件是os.getpid()(进程pid)与

    threading.get_ident()(线程标识符),如果每次acquire时的pid与ident都相同的时,即可成功。那么就可以在相同的进程中无限次数的acquire,但是多少次acquire就得多少次的release,防止死锁。

    那么是使用Lock还是RLock呢?这个要具体的看实际情况,并不是谁就一定好。

    总结

    本次推文中介绍了diskcache中FanoutCache 缓存分片、双端队列dedue、Index、Lock以及RLock。

    大家可以在实际中灵活运用,diskcache缓存的优势还是很大的,无需安装其他的模块,并且在文件管理器中能直接查看,还可以利用缓存的一些特性使用多线程的去实现业务等。

    但是也是有缺点的,即受制于本地文件系统的限制。每个磁盘每个目录下的文件数量是有限制的,所以需要结合实际情况使用。

    相关文章

      网友评论

          本文标题:Python 爬虫进阶篇——diskcahce缓存(二)

          本文链接:https://www.haomeiwen.com/subject/edqhwltx.html