REST API 是 在全世界使用標(biāo)準(zhǔn)化的消息格式。JSON 是互聯(lián)網(wǎng)上數(shù)據(jù)交換的基石,作為 JavaScript 的一個(gè)子集,它從一開始就獲得了巨大的推廣。它特別清晰易讀的語法也有利于推廣。
據(jù)我所知各種語言都有 JSON 庫用于序列化和反序列化。實(shí)際上在 Python 中就有很多種 JSON 庫。在下文中,我將為大家比較它們的異同。
引用庫
CPython 本身具有一個(gè) json 模塊。它最初是由 Bob Ippolito 作為 simplejson 開發(fā)的,并被合并到 Python 2.4 中(源代碼)。CPython 遵循 Python 軟件基金會(huì)(Python Software Foundation)許可協(xié)議。
simplejson 仍然作為一個(gè)單獨(dú)的庫存在,你可以通過 pip 安裝它。它是帶有可選 C 擴(kuò)展的純 Python 庫。Simplejson 遵循 MIT 和 Academic Free License(AFL)許可協(xié)議。
ujson 是對(duì) C 語言庫 Ultra JSON 的綁定。Ultra JSON 由 ESN(一家電子藝術(shù)工作室公司)開發(fā),并獲得了 3條款BSD許可。Ultra JSON 在 Github 上擁有 3k 星,305 個(gè) fork,50 個(gè)貢獻(xiàn)者,最近一次提交的日期只有 12 天,而最后一次提交是在 5 天之前發(fā)布的。我聽說它處于“維護(hù)模式”(來源),表明沒有新的進(jìn)展。
pysimdjson 是對(duì) C ++ 庫 simdjson 的綁定。SIMDjson 從加拿大獲得資助。simdjson 在 Github 上有 12.2k 顆星,611 個(gè)分支,63 個(gè)貢獻(xiàn)者,最后一次提交是 11 小時(shí)前,而最后一個(gè) issue 是 2 小時(shí)前創(chuàng)建的。
python-rapidjson 是對(duì) C ++ 庫 RapidJSON 的綁定。RapidJSON 由 騰訊 開發(fā)。RapidJSON 在 GitHub 上有 9.8k 個(gè)星,2.7k 個(gè) fork,150 個(gè)貢獻(xiàn)者,最近一次提交大約在 2 個(gè)月前,而最后一個(gè) issue 是 17 天前創(chuàng)建的。
orjson 是一個(gè) Python 軟件包,依靠 Rust 來完成繁重的工作。
成熟度和操作安全性
上面所有提到的庫都可以毫無問題地用作 benchmark 示例,切換 JSON 模塊也不是什么大問題,但我仍然想確定相關(guān)模塊是否支持。
CPython,simplejson,ujson 和 orjson 都認(rèn)為他們自己已經(jīng)可以投產(chǎn)了。
python-rapidjson 將自身標(biāo)記為 alpha,但是一位維護(hù)人員說這是一個(gè)錯(cuò)誤,并將很快得到修復(fù)(資源)。

問題
判斷一個(gè)庫的問題是否能夠被順利解決,一個(gè)直接的方式是直接去它的倉庫創(chuàng)建 issue,并觀察后續(xù)的跟進(jìn)反饋:
SimpleJSON:第二天我得到了答復(fù),回答很明確,易于理解,友善。Bob Ippolito 回答了我。他是最初開發(fā)這個(gè)庫的人,并且在 JSON 模塊的 Python 文檔中也提到了他!
uJSON:30分鐘內(nèi),我得到了一個(gè)清晰,友好,易于遵循的答案。@hugovank
ORJSON:10天沒有反應(yīng),然后關(guān)閉,沒有任何評(píng)論。
[PySIMDJSON]:15天后無人答復(fù)。
Python-RapidJSON:在30分鐘內(nèi),我得到了一個(gè)清晰,友好,易于遵循的答案。十天后合并了一個(gè)簡單的PR。
通過以上操作我得出一個(gè)答案,它們基本上沒有相互關(guān)系。
基準(zhǔn)測(cè)試(Benchmark)
為了正確地對(duì)不同的庫進(jìn)行基準(zhǔn)測(cè)試,我考慮了以下情況:
API:交換信息的 Web 服務(wù)。它可能包含 Unicode 并具有嵌套結(jié)構(gòu)。Twitter API 的 JSON 文件聽起來不錯(cuò),可以對(duì)此進(jìn)行測(cè)試。
API JSON錯(cuò)誤:我很好奇如果 JSON API 格式有錯(cuò)誤,性能會(huì)如何變化。因此,我在中間刪除了一個(gè)大括號(hào)。
GeoJSON:我首先通過一個(gè)開源街道地圖導(dǎo)出器 Overpass Turbo 得到了 GeoJSON 格式的 JSON 文件。你將獲得瘋狂多的 JSON 文件,這些文件大多具有坐標(biāo),而且還很嵌套。
機(jī)器學(xué)習(xí):只是大量的浮點(diǎn)數(shù)列表。這些可能是神經(jīng)網(wǎng)絡(luò)層的權(quán)重。
JSON行:結(jié)構(gòu)化日志在行業(yè)中大量使用。如果分析這些日志,可能需要遍歷千兆字節(jié)的數(shù)據(jù)。它們都是帶有日期時(shí)間對(duì)象、消息、記錄器、日志狀態(tài)等信息的簡單字集。
反序列化速度
我將我的硬盤驅(qū)動(dòng)器的讀取速度設(shè)置了一個(gè)較低的上限,在以下3個(gè)圖表中將以它作為基準(zhǔn)。





由此得出的結(jié)論是:
Rapidjson 速度很慢,但是對(duì)于像 twitter.json 這樣的小型 JSON,你不會(huì)注意到有什么不同。可以通過結(jié)構(gòu)化日志看到這一點(diǎn)。
simdjson,orjson 和 ujson 都快得驚人。
對(duì)于大多數(shù)庫而言,讀取包含結(jié)構(gòu)錯(cuò)誤的 JSON 文件的速度相同。一個(gè)值得注意的例外是 Rapidjson。我猜一旦發(fā)現(xiàn)錯(cuò)誤,它將中止讀取文件。
序列化速度
在這里,我預(yù)先創(chuàng)建了 JSON 字符串,并以寫入磁盤的時(shí)間作為基線測(cè)量了所需的時(shí)間。




我由此得出的結(jié)論是:
orjson 非常快,超級(jí)接近我的硬盤驅(qū)動(dòng)器寫入速度。ujson 也非常接近。
Rapidjson 也很快,但與 orjson 或 ujson 不在同一級(jí)別。
simdjson 很慢。
專業(yè)的 JSON 工作流
最后總結(jié)一下,我想指出一些我之前看到并記錄下來的問題:
-
調(diào)用變量
foo_json:JSON 是一種字符串格式。如果不是字符串,則不是 JSON。如果使用bar = json.loads(foo)反序列化 JSON,則 bar 不是 JSON。你可以將 bar 序列化為與 JSON
foo等效的 JSON,但 bar 不是 JSON,這是一個(gè) Python 對(duì)象,很像一個(gè)字典對(duì)象,就將它當(dāng)作foo_json。 屬性會(huì)在各處進(jìn)行檢查:如果你收到 JSON 數(shù)據(jù),很輕松就可以轉(zhuǎn)換為 Python 對(duì)象(例如字典)并使用它。這對(duì)于概念驗(yàn)證代碼或很小的 JSON 字符串來說是很好的選擇。如果你不將其轉(zhuǎn)換為 dataclass 之類的,它將一團(tuán)糟。
pydantic 是一個(gè)超級(jí)有用的驗(yàn)證庫。你可以使用自己喜歡的 JSON 庫將 JSON 字符串解析為帶有 字典/列表/字符串/數(shù)字/布爾值的 Python 基本表示形式,然后再使用 Pydantic 對(duì)其進(jìn)行解析。這樣做的好處是你知道以后要處理的內(nèi)容。不再只是將 Dict[str, Any] 用作 type annotation,不再用沒用的的編輯器自動(dòng)完成,不再檢查屬性是否在整個(gè)代碼中都存在。
要引入除默認(rèn) json 以外的其他 json 包,我建議使用此模式

對(duì)于 Flask,你可以使用其他 編碼器/解碼器,如下所示:

今天的內(nèi)容就到這里啦,希望這篇文章對(duì)你有所幫助,喜歡不要忘記收藏、轉(zhuǎn)發(fā)、評(píng)論,點(diǎn)點(diǎn)關(guān)注哦!