代码之家  ›  专栏  ›  技术社区  ›  Bharel

每次更改时都会搁置写入磁盘吗?

  •  3
  • Bharel  · 技术社区  · 1 月前

    我希望在asyncio程序中使用shelve,我担心每次更改都会导致主事件循环停滞。

    虽然我不介意酸洗操作偶尔放缓,但磁盘写入可能会很大。

    搁置多久同步一次到磁盘?这是封锁行动吗?我必须打电话吗 .sync() ?

    如果我安排 sync() 要在不同的线程下运行,不同的asyncio任务可能会同时修改搁置,这违反了单线程写入的要求。

    2 回复  |  直到 1 月前
        1
  •  4
  •   ShadowRanger    1 月前

    shelve 默认情况下,由 dbm 模块,反过来由 一些 dbm 系统上可用的实现。也不是 搁置 模块,也不是 dbm 模块,尽一切努力减少写入;每次给键赋值都会导致写入。即使在 writeback=True ,这只是意味着新的任务被放置在缓存中 立即写信给支持者 dbm ; 写入它们是为了确保原始值存在,并且创建缓存条目是因为分配的对象在分配后可能会发生变化,需要像新读取的对象一样处理(这意味着当 sync ed或 close d、 以防发生变化)。

    虽然有可能实现底层 dbm 库可能包括一些缓存、AFAICT,大多数库确实会尝试立即写入(即,在没有用户模式缓冲的情况下立即将数据推送到内核),但它们不一定强制立即同步到磁盘(尽管可以请求,例如 gdbm_sync ).

    回写=真 会使情况变得更糟,因为当它 同步 ,这是一项重大的工作(它实际上重写了自上次以来读取或写入数据库的每个对象 同步 ,因为它无法知道其中哪些可能已被修改),而不是一次重写单个键/值对。

    简而言之,如果你真的担心阻塞写入,你不能在没有潜在阻塞的情况下使用无线程异步代码,但只要 回写=真 不参与(或者只要你不参与 同步 / 关闭 直到性能考虑不再相关)。如果你需要真正的非阻塞异步行为, 全部的 搁置 交互需要在工作线程中的锁下发生,并且 writeback 必须是 False (为避免赛道条件酸洗数据)或 写回 True ,您必须注意避免修改 任何 在缓存期间可能存在的对象 同步 / 关闭 .

        2
  •  3
  •   Barmar    1 月前

    每次更新时,它都会写入磁盘 shelve 对象本身。所以如果你这样做

    shelf[key] = something
    

    shelf.update(somedict)
    

    它将写入文件。

    但是,如果字典中有可变值,修改它们不会触发对文件的写入。Python中的对象没有对引用它们的容器的任何引用,因此shelve对象无法检测到这些更改并写入文件。如果你需要在字典中支持可变值,你应该使用 writeback=True 创建搁置时的选项,以创建内存缓存;然后,每当您 sync() close() .