【问题标题】:Python: performance of custom JSON decoderPython:自定义 JSON 解码器的性能
【发布时间】:2012-09-06 20:15:22
【问题描述】:

我有一个应用程序,它使用标准 JSON 工具定期将 JSON 文件转储并加载到 Python 中。

在早期,我们决定将加载的 JSON 数据作为对象而不是字典来处理要方便得多。这实际上归结为“点”成员访问的便利性,而不是字典键查找的[] 符号。 Javascript 的优点之一是字典查找和成员数据访问之间没有真正的区别(我猜这就是 JSON 特别适合 Javascript 的原因)。但在 Python 中,字典键和对象数据成员是不同的东西。

因此,我们的解决方案是使用自定义 JSON 解码器,该解码器使用 object_hook 函数返回对象而不是字典。

我们从此过上了幸福的生活……直到现在,这个设计决定可能被证明是一个错误。您会看到,现在 JSON 转储文件变得相当大(> 400 MB)。据我所知,标准的 Python 3 JSON 工具使用本机代码来进行实际解析,因此它们非常快。但是,如果您提供自定义 object_hook,它仍然必须为每个解码的 JSON 对象执行解释的字节码 - 这严重减慢了速度。如果没有object_hook,解码整个 400 MB 文件只需大约 20 秒。但是用钩子的话,需要半个多小时!

所以,此时我想到了 2 个选项,这两个选项都不是很令人愉快。一种是忘记使用“点”成员数据访问的便利性,而只使用 Python 字典。 (这意味着要更改大量代码。)另一个是编写一个 C 扩展模块并将其用作object_hook,看看我们是否得到任何加速。

我想知道是否有一些我没有想到的更好的解决方案 - 也许是一种更简单的方法来获得“点”成员访问权限,同时仍然最初解码为 Python 字典。

对这个问题有什么建议和解决方案吗?

【问题讨论】:

  • 必须是 JSON 吗?您可以考虑使用pickle module;它可以让你存储和恢复整个 python 对象。 shelvemarshall 也可能满足您的需求。
  • 在用 C 语言编写之前,您可以尝试cython
  • 尝试分析代码并优化?
  • @Martijn Peters,使用 JSON 是与应用程序之外的数据互操作性的原始要求。不幸的是,Python 特定的泡菜格式不是一个选项。
  • @Channel72:好的,要求就是要求。

标签: python json python-3.x


【解决方案1】:

我取决于使用情况。

Lennart Regebro 解决方案非常适用于普通字典案例(您的案例可能并非如此)。否则,您需要实现递归解决方案。 但在这种情况下,python 将为您的 json 中的每个字典创建一个类。

nemo 的解决方案更“懒惰”/“按需”,所以如果您不打算使用字典的每个字段,我会选择 nemo 的解决方案。但是为嵌套字典和数组修改它。

def __getattr__(self, attr):
  ...
  if isinstance(self.__d[attr], dict):
    return DictWrap(self.__d[attr])

  elif isinstance(self.__d[attr], list):
    return ListWrap(self.__d[attr])    # and create similar wrapper for List.
  ...

普通字典的另一种解决方案是:

class JsonData(object):pass

data = JsonData()
data.__dict__.update(json.parse(data))

【讨论】:

    【解决方案2】:

    使用返回的原生 JSON 模块的 dict 并用提供点访问的对象包装它呢?

    你可以这样做:

    class DictWrap(object):
    
    def __init__(self, d):
        self.__d = d
    
    def __getattr__(self, attr):
        try:
            return self.__d[attr]
        except KeyError:
            raise AttributeError
    
    
    dw = DictWrap({"a": "foo", "b": "bar"})
    
    print dw.a, dw.b // foo bar
    print dw.c // AttributeError
    

    编辑:刚刚看到 Lennart Regebro 的回答,我会去的。

    【讨论】:

      【解决方案3】:

      您可以尝试不使用 object_hook,而是让 json 返回一个字典,然后将该字典转储到一个命名元组中。

      类似这样的:

      from collections import namedtuple
      result = json.parse(data)
      JsonData = namedtuple("JsonData", result.keys())
      jsondata = JsonData(**result)
      

      我不知道那会是什么速度,但值得一试。

      【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-07-27
      • 2010-10-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-02-15
      • 2020-12-07
      • 1970-01-01
      相关资源
      最近更新 更多