2016-06-16 2 views
8

파이썬 객체에 json 문자열을 비 직렬화하는 데 simplejson을 사용하고 있습니다. json을 내 도메인 객체로 역 직렬화하는 것을 담당하는 맞춤 작성된 object_hook이 있습니다.파이썬 객체에 거대한 json 문자열을 비 직렬화

내 json 문자열이 거대한 경우 (즉, 서버가 json 문자열 형태로 약 800,000 개의 도메인 객체를 반환하는 경우) 내 파이썬 디시리얼라이저가 약 10 분 동안 비 직렬화됩니다.

나는 조금 더 뚫어졌고, 단순한 것 같아. 그런데 많은 일을하지는 않고 모든 것을 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__에 직접 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 

_object_hook이 반환되기 전에 dct에 대한 참조가 손실되므로 다른 참조로 수정되는 것에 대해 걱정할 필요가 없습니다.

이것은 물론 __init__의 설정을 변경하는 것입니다. 클래스의 속성은 정확히 dct의 항목에 따라 다릅니다. 그것은 당신에게 달려 있습니다.


또한 (신원 확인이 더 파이썬은 그래서 하나의 None 오브젝트가) cls is not Nonecls != None 대체 할 수

시험을 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

찾아 주셔서 감사합니다. 당신의 제안으로 object_hook 직렬화 시간을 2 분 줄여 줄 수 있습니다. 그러나 여전히 800K에 대한 최종 종료 시간은 ~ 8 ​​분입니다. 나는 object_hook이 simplejson "3709170"번에 의해 호출 된 800K 레코드를 봅니다. 이 호출을 줄이기 위해 최적화 된 프레임 워크가 있는지 궁금합니다. lambdaJSON (jsontree/jsonpickle 또는 기타 프레임 워크)에 대한 생각 – pragnya

+0

@pragnya'lamdaJSON'과 잘 작동하는 경우, 앞으로도 똑같은 문제점을 가지고있는 다른 사람들을 위해 해킹을 게시 할 수 있습니다. –