python - 将一个巨大的json字符串反序列化为python对象

标签 python json performance python-2.7 simplejson

我正在使用 simplejson 将 json 字符串反序列化为 python 对象。我有一个自定义编写的 object_hook,负责将 json 反序列化回我的域对象。

问题是,当我的 json 字符串很大时(即服务器以 json 字符串的形式返回大约 80 万个域对象),我的 python 反序列化器需要将近 10 分钟来反序列化它们。

我进一步深入研究,看起来 simplejson 本身并没有做太多工作,而是将所有内容都委托(delegate)给了 object_hook。我尝试优化我的 object_hook 但这也没有提高我的性能。 (我几乎没有得到 1 分钟的改进)

我的问题是,我们是否有任何其他经过优化以处理庞大数据集的标准框架,或者是否有一种方法可以让我利用框架的功能而不是在 object_hook 级别做所有事情。

我看到没有 object_hook 框架只返回一个字典列表而不是域对象列表。

此处的任何指示都会有用。

仅供引用,我使用的是 simplejson 版本 3.7.2

这是我的示例 _object_hook:

def _object_hook(dct):
    if '@CLASS' in dct: # server sends domain objects with this @CLASS 
        clsname = dct['@CLASS']
        # This is like Class.forName (This imports the module and gives the class)
        cls = get_class(clsname)
        # As my server is in java, I convert the attributes to python as per python naming convention.
        dct = dict( (convert_java_name_to_python(k), dct[k]) for k in dct.keys())
       if cls != None:
            obj_key = None
            if "@uuid"in dct
                obj_key = dct["@uuid"]
                del(dct["@uuid"])
            else:
                info("Class missing uuid: " + clsname)
            dct.pop("@CLASS", None)

            obj = cls(**dct) #This I found to be the most time consuming process. In my domian object, in the __init__ method I have the logic to set all attributes based on the kwargs passed 
            if obj_key is not None:
                shared_objs[obj_key] = obj #I keep all uuids along with the objects in shared_objs dictionary. This shared_objs will be used later to replace references.
        else:
            warning("class not found: " + clsname)
            obj = dct

        return obj
    else:
        return dct

示例响应:

    {"@CLASS":"sample.counter","@UUID":"86f26a0a-1a58-4429-a762-  9b1778a99c82","val1":"ABC","val2":1131,"val3":1754095,"value4":  {"@CLASS":"sample.nestedClass","@UUID":"f7bb298c-fd0b-4d87-bed8-  74d5eb1d6517","id":1754095,"name":"XYZ","abbreviation":"ABC"}}

我有多层嵌套,我从服务器接收的记录数超过 800K。

最佳答案

我不知道有什么框架可以开箱即用,但您可以对类实例的设置方式进行一些优化。

由于将字典解压缩为关键字参数并将它们应用于您的类变量占用了大量时间,您可以考虑将 dct 直接传递给您的类 __init__并使用 dct 设置类字典 cls.__dict__:

试验 1

In [1]: data = {"name": "yolanda", "age": 4}

In [2]: class Person:
   ...:     def __init__(self, name, age):
   ...:         self.name = name
   ...:         self.age = age
   ...:
In [3]: %%timeit
   ...: Person(**data)
   ...:
1000000 loops, best of 3: 926 ns per loop

试验 2

In [4]: data = {"name": "yolanda", "age": 4}

In [5]: class Person2:
   ....:     def __init__(self, data):
   ....:         self.__dict__ = data
   ....:
In [6]: %%timeit
   ....: Person2(data)
   ....:
1000000 loops, best of 3: 541 ns per loop

不用担心 self.__dict__ 被另一个引用修改,因为对 dct 的引用在 _object_hook 返回之前丢失了。

这当然意味着更改您的 __init__ 的设置,您的类的属性严格取决于 dct 中的项目。这取决于你。


您也可以将 cls != None 替换为 cls is not None(只有一个 None 对象,因此身份检查更重要 python ):

试验 1

In [38]: cls = 5
In [39]: %%timeit
   ....: cls != None
   ....:
10000000 loops, best of 3: 85.8 ns per loop

试验 2

In [40]: %%timeit
   ....: cls is not None
   ....:
10000000 loops, best of 3: 57.8 ns per loop

你可以用一行替换两行:

obj_key = dct["@uuid"]
del(dct["@uuid"])

成为:

obj_key = dct.pop('@uuid') # Not an optimization as this is same with the above

在 80 万个域对象 的规模上,这些会为您节省一些获取object_hook 以更快地创建对象的好时间。

关于python - 将一个巨大的json字符串反序列化为python对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37861698/

相关文章:

python - networkX 中最大的弱连接组件

python - 如何从 pandas 的日期列中查找不匹配的值

python - 如何将具有值作为字典的列拆分为新列(具有 NaN 值)

performance - 使用自定义 API 进行排序 -removeAndAppend

python - 如何将 sqlite3 模块导入 Python 2.4?

java - Postman 在使用 REST Api 时出现意外的 'S'

java - 使用 GSON 从 Java 中的 JSON 字符串获取值

ios - 如何在 Swift 中的 NSJSONSerialization.dataWithJSONObject 之后获得可读的 JSON

sql-server - 合并与选择比插入更新性能比较

php - 在同一页面中组合特定页面样式和全局样式时的性能