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

使内存中的数据与长时间运行的Python脚本的文件保持同步

  •  2
  • Blixt  · 技术社区  · 14 年前

    我有一个Python(2.7)脚本作为服务器,因此它将运行很长一段时间。这个脚本有一系列的值来跟踪,这些值可以根据客户机输入随时更改。

    理想情况下,我追求的是能够保持Python数据结构(具有类型值 dict , list , unicode , int float JSON,基本上)在内存中,允许我根据自己的需要更新它(除了多次引用任何引用类型实例之外),同时将此数据保持在人类可读文件中的最新状态,以便即使拔下电源插头,服务器也可以启动并继续使用相同的数据。

    我知道我说的基本上是一个数据库,但我保存的数据将非常简单,而且大多数情况下可能小于1KB,所以我正在寻找最简单的解决方案,可以为我提供所描述的数据完整性。有没有好的Python(2.7)库允许我做这样的事情?

    5 回复  |  直到 9 年前
        1
  •  2
  •   fmark    14 年前

    我同意你不需要一个完整的数据库,因为 似乎你只需要写原子文件 . 您需要从两个部分解决这个问题:序列化/反序列化和原子写入。

    对于第一部分, json ,或 pickle 可能是适合你的格式。JSON具有可读性的优点。但这似乎并不是你面临的主要问题。

    一旦你将对象序列化为字符串, 使用以下过程以原子方式将文件写入磁盘,假设只有一个并发写入程序 (至少在POSIX上,见下文):

    import os, platform
    backup_filename = "output.back.json"
    filename = "output.json"
    
    serialised_str = json.dumps(...)
    with open(backup_filename, 'wb') as f:
         f.write(serialised_str)
    if platform.system() == 'Windows':
         os.unlink(filename)
    os.rename(backup_filename, filename)
    

    os.rename 将覆盖现有文件并在POSIX上是原子的,这在Windows上是不可悲的。在窗户上,有可能 os.unlink 会成功的,但是 操作系统重命名 会失败,意味着你只有 backup_filename 而不是 filename . 如果您针对Windows,则在检查是否存在Windows时需要考虑这种可能性。 文件名 .

    如果存在多个并发写入程序的可能性,则必须考虑同步构造。

        2
  •  4
  •   Frédéric Hamidi    14 年前

    好吧,既然你知道我们基本上是在讨论一个数据库,尽管它是一个非常简单的数据库,你可能不会感到惊讶,我建议你看看 sqlite3 模块。

        3
  •  2
  •   Peter Gibson    14 年前

    人类可读性要求的原因是什么?

    我建议在sqlite中寻找简单的数据库解决方案,或者在pickle中寻找序列化对象并将其写入磁盘的简单方法。不过,这两种语言都不是特别适合人类阅读的。

    其他选项是JSON或XML,正如您所暗示的那样-使用内置的JSON模块序列化对象,然后将其写入磁盘。启动时,请检查该文件是否存在,并在需要时加载数据。

    docs :

    >>> import json
    >>> print json.dumps({'4': 5, '6': 7}, sort_keys=True, indent=4)
    {
        "4": 5,
        "6": 7
    }
    
        4
  •  1
  •   Rafael Almeida Andre Goncalves    14 年前

    既然你提到你的数据很小,我就用一个简单的解决方案 pickle 模块,用于将python对象转储到行中 very easily .

    然后你就建立了一个 Thread 以定义的时间间隔将对象保存到文件中。

    不是一个“图书馆”的解决方案,但-如果我理解你的要求-简单到你不需要一个。

    编辑:您提到您希望覆盖在编写过程中出现问题的情况,从而有效地使它成为一个原子事务。在这种情况下,传统的方法是使用“基于日志的恢复”。它实质上是将一条记录写到一个日志文件中,上面写着“write transaction started”,然后在完成后写下“write transaction comitted”。如果“started”没有对应的“commit”,则回滚。

    在这种情况下,我同意使用SQLite这样的简单数据库可能会更好。这可能有点过火,但另一方面,实现原子性本身可能会重新发明轮子一点(我没有发现任何明显的库可以为您做到这一点)。

    如果你真的决定采用这种狡猾的方式,这个主题将在Silberschatz的操作系统手册的进程同步一章的“原子事务”一节中介绍。

    一个非常简单的(虽然可能不是“事务上完美的”)替代方法就是每次都记录到一个新文件中,这样如果一个文件损坏了你就有一个历史记录。您甚至可以为每个文件添加一个校验和,以自动确定它是否已损坏。

        5
  •  0
  •   Jesse Dhillon    14 年前

    您正在询问如何实现一个数据库,该数据库提供 ACID 保证,但你没有提供一个很好的理由,为什么你不能使用现成的。SQLite非常适合这种情况,并为您提供了这些保证。

    但是,有 KirbyBase . 我从来没有用过它,我不认为它能保证酸性,但它确实有一些你想要的特性。