Faster JSON - orjson | Python 主題月

本文正在參加「Python主題月」,詳情查看 活動連接python

微信公衆號搜索【程序媛小莊】,Rest cannot be enjoyed by lazy people~git

前言

JSON使用的越多就越可能遇到JSON編碼或者解碼的瓶頸,Python的內置json庫雖然也很好用可是也有不少其餘更快的JSON庫可使用,可是具體選擇哪個或者哪種須要根據具體狀況,沒有一種標準的規則衡量哪種JSON最好或者最快,由於不一樣的項目有不一樣的需求,有的注重安全有的注重速度更快,本文介紹更快的json-orjsongithub

orjson簡介

orjson是一個更加快速的Python JSON庫,經過基準測試發現比標準json庫和rapidjson的速度更快,能夠序列化dataclass datetime numpy UUIDjson或者rapidjson相比orjson序列化獲得的結果是bytes類型而不是json格式的str類型,序列化時不會將unicode轉換成ASCII,須要注意的是,orjson不提供dump/load方法實現對file-like對象進行序列化和反序列化。更多關於orjson的使用請參考官方文檔web

json rapidson和orjson速度對比

下面是json rapidjson orjson進行的基準測試代碼以及結果。json

import json
import orjson
import rapidjson
import time

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(module_name, dumps):
    start = time.time()
    for i in range(100000):
        dumps(m)
    print(module_name, time.time() - start)


benchmark('json', json.dumps)
benchmark('rapidjson', rapidjson.dumps)
benchmark("orjson", lambda s: str(orjson.dumps(s), "utf-8"))  # orjson只能輸出bytes
複製代碼

而且結果以下,orjson即便須要額外的Unicode解碼也是最快的,可是並不表明博主必定推薦您使用orjson,須要根據實際狀況進行選擇哦~:api

json 1.1019978523254395
rapidjson 0.25800156593322754
orjson 0.0859987735748291
複製代碼

orjson基本使用

orjson安裝

安裝命令很是簡單:pip install orjson瀏覽器

須要注意的是,在Linux環境中使用pip命令安裝時pip版本須要大於19.3,所以在安裝orjson時能夠先更新pip版本。安全

orjson基本使用

序列化-dumps

和Python標準JSON庫json相比最大的不一樣在於orjson.dumps返回的結果的是bytesjson.dumps返回的結果是strsort_keys參數被option=orjson.OPT_SORT_KEYS代替,indent參數被option=orjson.OPT_INDENT_2代替而且不支持其餘indent等級。微信

def dumps( __obj: Any, default: Optional[Callable[[Any], Any]] = ..., option: Optional[int] = ..., ) -> bytes: ...
    
# 序列化
import orjson

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


res = orjson.dumps(m)
print(res)  
# b'{"timestamp":1556283673.1523004,"task_uuid":"0ed1a1c3-050c-4fb9-9426-a7e72d0acfc7","task_level":[1,2,1],"action_status":"started","action_type":"\xe5\x93\x88\xe5\x93\x88","key":"value","another_key":123,"and_another":["a","b"]}'
複製代碼

反序列化-loads

loads方法將bytes類型的JSON格式數據反序列化稱爲Python示例對象。markdown

print(orjson.loads(res))
複製代碼

float int str類型的序列化和反序列化

float

orjson在序列化和反序列化雙精度浮點數時不會損失精度,在json rapidjson中一樣不會損失精度。orjson.dumps對序列化Nan,Infinity,-Infinity不兼容,會獲得null的結果,可是json和rapidjson支持。

>>> import orjson, ujson, rapidjson, json
>>> orjson.dumps([float("NaN"), float("Infinity"), float("-Infinity")])
b'[null,null,null]'
>>> rapidjson.dumps([float("NaN"), float("Infinity"), float("-Infinity")])
'[NaN,Infinity,-Infinity]'
>>> json.dumps([float("NaN"), float("Infinity"), float("-Infinity")])
'[NaN, Infinity, -Infinity]'
複製代碼

int

orjson默承認以序列化和反序列化64-bits的證書,支持的範圍是帶符號的最小值(-9223372036854775807)到無符號的最大值(18446744073709551615),可是在某些場景下只支持53-bits的證書,好比web瀏覽器,對於不兼容的部分,dumps方法會拋出JSONEncodeError異常。

>>> import orjson
>>> orjson.dumps(9007199254740992)
b'9007199254740992'
>>> orjson.dumps(9007199254740992, option=orjson.OPT_STRICT_INTEGER)
JSONEncodeError: Integer exceeds 53-bit range
>>> orjson.dumps(-9007199254740992, option=orjson.OPT_STRICT_INTEGER)
JSONEncodeError: Integer exceeds 53-bit range
複製代碼

str

orjson和UTF8具備嚴格的一致性,比Python的標準庫json更爲嚴格,json在序列化和反序列化時使用UTF-16進行代理,可是這是不可用的UTF8。若是orjson.dumps的參數傳了一個不是UTF8的字符那麼會拋出orjson.JSONEncodeError異常,若是orjson.loads()的參數收到了不可用的UTF8字符也會拋出一樣的異常。

orjson和rapidjson和Python標準庫json相比來講,對於不符合規則的輸入始終都會拋出相應的異常。

爲了程序的健壯性,能夠在反序列化時先將bytes類型編碼成成UTF8格式。

>>> import orjson
>>> orjson.loads(b'"\xed\xa0\x80"')
JSONDecodeError: str is not valid UTF-8: surrogates not allowed
>>> orjson.loads(b'"\xed\xa0\x80"'.decode("utf-8", "replace"))
複製代碼

結語

文章首發於微信公衆號程序媛小莊,同步於掘金

碼字不易,轉載請說明出處,走過路過的小夥伴們伸出可愛的小指頭點個贊再走吧(╹▽╹)

image.png

相關文章
相關標籤/搜索