2016-06-16 80 views
8

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

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

我向下钻了一点,它看起来像simplejson,因为它没有做很多工作,而是将所有东西委托给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。

+0

看起来很有趣。任何样本片段可以快速检查它,这将会很有用。 –

+0

如果您可以发布您的'object_hook'函数的代码以及您想要解析的JSON样本,那将有助于我们回答您的问题。 – jstlaurent

回答

6

我不知道任何框架都能提供您开箱即用的内容,但您可以对您的类实例的设置方式进行一些优化。

由于拆包字典为关键字参数,并把它们应用到你的类变量,走的是散的时候,你可以考虑直接传递dct__init__类,并建立类字典cls.__dict__dct

试验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 != Nonecls 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 

在800K 域对象的规模,这会节省你一些让object_hook更快地创建对象的好时机。

+1

感谢您的关注。根据您的建议,我可以减少2分钟的object_hook反序列化时间。但800K的最终时间仍然是〜8分钟。我看到800K记录,我的object_hook被simplejson“3709170”调用次数。我想知道是否有任何优化的框架可以减少这种调用。关于lambdaJSON(jsontree/jsonpickle或任何其他框架)的任何想法 – pragnya

+0

@pragnya如果它与'lamdaJSON'很好地结合在一起,你可以发布你的黑客作为对未来可能有同样问题的其他人的答案。 –

相关问题