V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
爱意满满的作品展示区。
Sailwww
V2EX  ›  分享创造

一个 Python 库,轻量的,基于 sqlite 的持久化 list, dict

  •  
  •   Sailwww · 2022-03-14 12:29:23 +08:00 · 3040 次点击
    这是一个创建于 1010 天前的主题,其中的信息可能已经有所发展或是发生改变。

    https://github.com/sailist/dbrecord

    前一段时间训练文本数据集,为了方便 shuffle 操作整出来的,这两天简单重构后分享一下。

    主要特性:

    • 接口友好,提供 python list, dict 中大部分的(增改查)相关的操作方法
    • 基于 sqlite ,使用简单,安装即可使用,不需要任何配置,一个文件可带走
    • list 和 dict 基于相同的底层数据表,提供了尽可能兼容的互相转换操作,可以用 index 读 dict (可以看成是 OrderedDict ),也可以用 key 读 list ( list append 时候 key 是相应的 ns 时间戳)。
    • 轻量:不到 500 行的代码(大概有一定的学习用途)
    • 测试完善

    用途:

    • 可以用于构建配置文件
    • 存储只有 key 或者 index 检索需求的数据(比如我曾经用于构建文本训练数据)

    感兴趣可以关注一下: https://github.com/sailist/dbrecord

    14 条回复    2022-03-16 18:56:43 +08:00
    Sailwww
        1
    Sailwww  
    OP
       2022-03-14 13:31:11 +08:00
    补一条,sqlite 支持亿量级的数据低延迟索引读取,所以该库也有类似的性能表现,在一些场景下是替代 json 等数据格式的更好选择
    BingoXuan
        2
    BingoXuan  
       2022-03-14 14:07:13 +08:00
    Shazoo
        3
    Shazoo  
       2022-03-14 16:20:24 +08:00
    协程支持?多线程支持? multiprocess ?
    Sailwww
        4
    Sailwww  
    OP
       2022-03-14 18:08:18 +08:00
    @BingoXuan 还真是,才发现有这个...对比了一下,基本确实是在重复造轮子,不过还是总结一下区别
    - 在 io 上,因为我建的是双层索引,同时还有 id 自增列,所以在单值读取上慢了很多(但也在 1e-5 量级内,btw ,sqlitedict 是 1e-9 量级),数据库大小同量级下(因为索引)应该也大一些;优点是可以通过 list 的接口读取。
    - 多值上它没有提供接口,在同时读取多个 key 或者 index 的场景下,我比他快 10 倍以上
    - 整体上这个库算是一个 sqlite 小玩具,里面还提供了一个二分求数据库大小的函数,在无自增 id 缺失的情况下,比 select count(*) 要快 1000 倍左右
    Sailwww
        5
    Sailwww  
    OP
       2022-03-14 18:22:44 +08:00
    @Shazoo
    只有读操作支持,这个当初就是为了我读训练模型时候用的,没有多进程支持速度还是瓶颈...多线程和协程理应也支持?话说这个支持也就是 fork 的时候重建链接就可以了,也不需要别的操作....
    写操作这个是 sqlite 本身的问题,我没遇到使用场景,自己维护锁就没必要了
    bnm965321
        6
    bnm965321  
       2022-03-15 09:59:15 +08:00
    代码写的挺好的,不过我觉得这种场景不如使用 redis/leveldb
    frinstioAKL
        7
    frinstioAKL  
       2022-03-16 11:29:20 +08:00
    有趣, 问下楼主有试过和 lmdb 对比么
    frinstioAKL
        8
    frinstioAKL  
       2022-03-16 11:37:47 +08:00
    最近也考虑同样的场景需求, 正准备自己造轮子结果楼主已经先行一步了.
    除了上面的和 lmdb 对比外, 楼主要不要试试把 pickle 序列化改成用 quickle?( https://github.com/jcrist/quickle) 看 stackoverflow, quickle 易用性和速度似乎是权衡比较好的

    嘿嘿, 等楼主反馈结果(白嫖)
    Sailwww
        9
    Sailwww  
    OP
       2022-03-16 14:34:20 +08:00
    @bnm965321 多谢认可和建议,打算学一下 leveldb 的实现

    @frinstioAKL lmdb 好像不能按 index 索引,是分块的吧?如果是 lmdb 的那种实现,不如尝试和 feather 格式对比(个人理解)

    quickle 试了一下,两个差的不多,quickle 读比 pickle 快 7% ,pickle 写比 quickle 快了 7% (有上下浮动),所以看具体使用场景吧。

    我记得之前有哪个组做强化学习的,为了搞一个分布式系统开源了一个序列化的库好像效率更高,但我一时半会找不到了...
    Sailwww
        10
    Sailwww  
    OP
       2022-03-16 14:37:44 +08:00
    @frinstioAKL 哦抱歉,我记错了,不是分块读取的;我之前用过 lmdb ,不知道是不是之前代码写的烂的缘故,我记得 lmdb 单个文件数据存储,量级越大读起来就越慢...也是因为当初这件事,我后来尝试了 feather 格式,然后出来了这个库...
    frinstioAKL
        11
    frinstioAKL  
       2022-03-16 16:14:49 +08:00
    @Sailwww 谢谢反馈~ quickle 读写快 7% 感觉还是很可观, 写入速度我倒不是很在意. lmdb 量级越大读起来越慢, 请问你这边是遇到了多大的量级呢? 有空我也试试在我的使用场景下对比下, 试试你的库, 再反馈给你
    Sailwww
        12
    Sailwww  
    OP
       2022-03-16 17:52:56 +08:00
    @frinstioAKL 我刚刚路上突然想到一点,我的测试可能有一定错误,因为我存的是数字,可能因为数据太小导致写入速度慢?(这种数据大小导致的某种均匀性我最初还是在 hash 方法里见到的)。我去看了 quickle 提供的 benchimark ,它在 dump 和 load 下好像都是有速度优势的。我看了 @BingoXuan 说的 sqlitedict 的实现,或许可以考虑直接提供一个 backend 参数传入..

    lmdb 当初应该有一两百万了吧,忘了是纯文本场景还是文本图像混合场景了,哦对了 lmdb 里面有个 metadata 空间应该也有上限,当初我好像是用来放 label 的,这个也是弃掉的一个原因。 [随便找了一篇说明文档]( https://mozilla.github.io/firefox-browser-architecture/text/0015-rkv.html#:~:text=LMDB%20by%20default%20has%20a,may%20have%20performance%20impact%20too.)

    > LMDB by default has a maximum key size set as 512 bytes, there is a compile time configuration to change it, though a larger key may have performance impact too
    frinstioAKL
        13
    frinstioAKL  
       2022-03-16 18:21:15 +08:00
    @Sailwww 受教了, lmdb 的 key 居然有大小限制, 这个我还真没超过这个限制过. 我这边存储 metadata 时一般加一个类似于 __labels__, __keys__ 这样的 key, 对应的 value 去存储实际的 label 等信息. 我这边几百万图片超过 500G LMDB 存储, 放 pytorch dataloader 里面暂时没遇到性能瓶颈. 基于 sqlite 的方案我倒是很想试试
    Sailwww
        14
    Sailwww  
    OP
       2022-03-16 18:56:43 +08:00
    @frinstioAKL 似乎因为编解码方式的问题,图片的 sqlite 读取性能好像不是很客观,而且十分占空间,当时踩完坑后采取的是将图片保存成一个 chunk ,然后 sqlite 记录 chunk path 然后读。因为那段时间工期太赶没仔细测试,你可以再试验一下,我也等一波反馈~
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2507 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 15:52 · PVG 23:52 · LAX 07:52 · JFK 10:52
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.