在Python中使用json.dumps(data)时,突然发现很慢。数据本身并不大,但它是一个包含很多元素的列表,所以我正在寻找一个替代的JSON处理库。.我大致比较了一个ujson(UtltraJSON)、python-rapidjson(RapidJSON)和Python自带的json库。还有一个simplejson是为了兼容Python2.6(json是Python2.6新增的API),性能有些差。基本上,生姜还是老辣。如果想要获得更好的性能,就不得不依赖于传统的C/C++语言。ujson是用纯C写的,RapidJSON是用C++写的。后者依然是十美分的开源产品。json、ujson、rapidjson的loads()方法性能差异并不明显,但是Python自带的json库在dumps()大对象时会考验用户的耐心。注:一开始认为ujson是最好的选择,所以我们先从usjon和rapidjson入手。后来在写这篇文章的过程中,从usjon的自我介绍中发现Rust写的orjson很显眼,于是加了orjson测试,看来orjson更值得拥有。以上三个json组件的安装方法是pipinstallpython-rapidjson$pipinstallsimplejson我测试了ujson、rapidjson和Pythonjson库的dumps()性能,simpejson没多想。测试代码如下#test.pyfromtimeimporttimeimportsysimportstringnum=int(sys.argv[1])lib=sys.argv[2]items=[]foriinrange(num):items.append({c:cforcinstring.ascii_letters})start=time()iflib=='ujson':importujsonujson.dumps(items)eliflib=='rapidjson':importrapidjsonrapidjson.dumps(items)else:importjsonjson.dumps(items)print(time()-start)执行python1000|10000|100000|1000000json|ujson|rapidjson,测试结果统计如下(数字为不同情况下的耗时):测试性能基本与PythonJSON库Benchmark一致.原文截取两张图如下:UltraJSON的Github项目页面上也有对比ujson、nujson、orjson、simplejson、json的Benchmarks。列出的orjson(pipinstallorjson)和nujson(pipinstallnujson,ForkUltraJSON支持Numpy序列化)性能不错,orjson性能优于ujson。看到orjson后赶紧做个对比测试,在上面的test.py代码中加入eliflib=='orjson':importorjsonorjson.dumps(items),然后列出完整的对比数据,继续浏览orjson的Github主页ijl/orjson,既不是用C也不是C++写的,而是用Rust语言写的,真是让我眼前一亮,Rust程序的运行速度真是堪比C/C++。写到这里,我会开始改变我只认ujson的想法。Orjson可能是更好的选择。这篇文章的标题也由原来的“Python处理JSON。必要时我选择ujson(UltraJSON)”改为“Python处理JSON必要时我选择ujson和orjson”。这也是写博客尽可能多搜集素材的魅力所在。补充一下,orjson的dumps()函数使用方式略有不同,不再使用indent参数,返回值为bytes,所以格式化字符串的写法如下:importorjsonjson_str=orjson.dumps(record,option=orjson.OPT_INDENT_2).decode()另外,这里顺便记录一下使用ujson遇到的一个bug,就不另起炉灶了。反正我现在找东西不看标题,而是谷歌查到的内容。ujson3.0.0和3.1.0版本中dumps()的缩进参数无法正常工作,在3.0.0#415中有一个用于转储的openticket'indent'parameterdoesn'tindentproperly。比如使用ujson3.1.0时,现象为>>>importujson>>>ujson.dumps({'a':1,'b':2})'{"a":1,"b":2}'>>>ujson.dumps({'a':1,'b':2},indent=0)'{"a":1,"b":2}'>>>ujson.dumps({'a':1,'b':2},indent=1)'{\n"a":1,\n"b":2\n}'>>>ujson.dumps({'a':1,'b':2},indent=2)'{\n"a":1,\n"b":2\n}'>>>ujson.dumps({'a':1,'b':2},indent=8)'{\n"a":1,\n"b":2\n}'当缩进大于1时,会被认为是1,切换时没问题回到ujson2.0.3>>>importujson>>>ujson.dumps({'a':1,'b':2},indent=2)'{\n"a":1,\n"b":2\n}'>>>ujson.dumps({'a':1,'b':2},indent=8)'{\n"a":1,\n"b":2\n}'暂时使用pipinstallujson==2.0.3安装ujson2.0.3才解决这个问题,但是这个版本无法序列化datetime类型。
