2016-06-16 112 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'很好地結合在一起,你可以發佈你的黑客作爲對未來可能有同樣問題的其他人的答案。 –

相關問題