SW/Python

Python : 가장 빠른 JSON 라이브러리 선택 방법

얇은생각 2019. 10. 6. 07:30
반응형

JSON을 많이 사용할수록 병목 현상으로 JSON 인코딩 또는 디코딩이 발생할 가능성이 높아집니다. 파이썬의 내장 라이브러리는 나쁘지 않지만, 사용 가능한 더 빠른 JSON 라이브러리가 여러개 있습니다. 사용할 라이브러리를 어떻게 선택하면 좋을까요?

정답이없고, 모두를 지배 할 수 있는 가장 빠른 JSON 라이브러리가 없다는 것입니다.

"빠른 JSON 라이브러리"는 사용 패턴이 다르기 때문에 사람들마다 다르게 느낄 수 있습니다. 속도는 모든 것이 아닙니다. 보안 및 사용자 지정과 같은 다른 관심 사항도 있을 수 있습니다. 따라서 필요에 따라 가장 빠른 JSON 라이브러리를 선택할 수 있도록 Python에 대한 빠른 JSON 라이브러리를 선택하는 과정을 공유하고자 합니다. 이 프로세스를 사용하여 특정 요구에 가장 적합한 라이브러리를 선택할 수 있습니다.

 

1 단계 : 실제로 새로운 JSON 라이브러리가 필요할까요?

JSON을 사용한다고 해서 해당 병목 현상이 발생하는 것은 아닙니다. 어떤 JSON 라이브러리에 대해 생각하기 전에 파이썬의 내장 JSON 라이브러리가 특정 애플리케이션에서 실제로 문제가 된다는 증거가 필요합니다.

JSON 인코딩이 메시지 생성에 사용되는 CPU 시간의 25 %를 차지한다는 주장이 있습니다. 결론적으로 33 % 더 빠르게 실행될 수 있으며 (JSON 인코딩 시간이 0이 된 경우) 상당히 큰 시간입니다.

2 단계 : 벤치 마크 정의

다양한 JSON 라이브러리의 벤치 마크 페이지를 보면 다양한 메시지에서 어떻게 수행되는지에 대해 이야기합니다. 그러나 이러한 메시지가 반드시 사용 목적과 일치하는 것은 아닙니다. 매우 큰 메시지를 측정하는 경우가 많으며, 제 경우에는 작은 메시지에 관심을 두고 볼 수 있습니다.

따라서 특정 사용 패턴과 일치하는 측정 값을 제시하고자 합니다. 

1. 인코딩, 디코딩 또는 둘 다에 관심이 있습니까?
2. 작거나 큰 메시지를 사용하고 있습니까?
3. 일반적인 메시지는 무엇입니까?

생성한 로그 메시지의 특정 구조인 작은 메시지를 인코딩하는 데 주로 관심이 있습니다. 실제 로그를 기반으로 다음 샘플 메시지를 제안해보겠습니다.

{
    "timestamp": 1556283673.1523004,
    "task_uuid": "0ed1a1c3-050c-4fb9-9426-a7e72d0acfc7",
    "task_level": [1, 2, 1],
    "action_status": "started",
    "action_type": "main",
    "key": "value",
    "another_key": 123,
    "and_another": ["a", "b"],
}

 

 

3 단계 : 추가 요구 사항에 따라 필터링

성능이 전부는 아닙니다. 다른 관심사가있을 수도 있습니다.

1. 보안 / 충돌 방지 : 로그 메시지에는 신뢰할 수없는 출처에서 온 데이터가 포함될 수 있습니다. JSON 인코더가 잘못된 데이터에서 충돌하면 안정성이나 보안에 좋지 않습니다.

2. 사용자 지정 인코딩 : JSON 인코딩의 사용자 정의를 지원하므로 추가 종류의 Python 객체를 직렬화 할 수 있습니다. 일부 JSON 라이브러리는 이를 지원하지만 다른 JSON 라이브러리는 이를 지원하지 않습니다.

3. 크로스 플랫폼 : Linux, macOS, Windows에서 실행됩니다.

4. 유지 관리 : 적극적으로 지원되지 않는 라이브러리에 의존하고 싶지 않을 수 있습니다.

고려한 라이브러리는 orjson, rapidjson, ujson 및 hyperjson입니다. 위의 기준에 따라 이들 중 일부를 필터링해보았습니다.

ujson에는 충돌과 관련하여 제기된 많은 버그가 있으며, 수정된 버그조차도 2016년 이후 업데이트되지 않았기 때문에 항상 사용 가능한 것은 아닙니다.

hyperjson에는 macOS 용 패키지만 있으며 일반적으로 미숙합니다.

 

4 단계 : 벤치마킹

마지막 두 경쟁자는 rapidjson과 orjson이었습니다. 다음 벤치 마크를 실행했습니다.

import time
import json
import orjson
import rapidjson

m = {
    "timestamp": 1556283673.1523004,
    "task_uuid": "0ed1a1c3-050c-4fb9-9426-a7e72d0acfc7",
    "task_level": [1, 2, 1],
    "action_status": "started",
    "action_type": "main",
    "key": "value",
    "another_key": 123,
    "and_another": ["a", "b"],
}

def benchmark(name, dumps):
    start = time.time()
    for i in range(1000000):
        dumps(m)
    print(name, time.time() - start)

benchmark("Python", json.dumps)
# orjson only outputs bytes, but often we need unicode:
benchmark("orjson", lambda s: str(orjson.dumps(s), "utf-8"))
benchmark("rapidjson", rapidjson.dumps)

 

$ python jsonperf.py 
Python 4.829106330871582
orjson 1.0466396808624268
rapidjson 2.1441543102264404


추가 유니 코드 디코딩이 필요하더라도 orjson이 가장 빠릅니다 (이 특정 경우에 한해서) 

항상 그렇듯이 트레이드 오프가 있습니다. orjson은 rapidjson보다 사용자 수가 적으며 Conda 패키지가 없으므로 Conda-forge를 위해 직접 패키지해야 합니다. 하지만 훨씬 빠릅니다.

 

결론

orjson을 사용해야 할까요? 반드시 그런 것은 아닙니다. 요구 사항이 다르거나 벤치 마크가 다를 수 있습니다. 예를 들어 큰 파일을 디코딩해야 할 수 도 있습니다.

핵심 요소는 프로세스입니다. 특정 요구 사항, 성능 등을 파악하고 요구에 가장 적합한 라이브러리를 선택해보세요.

반응형