Python 我可以加速YAML吗?

Python 我可以加速YAML吗?,python,json,yaml,Python,Json,Yaml,我制作了一个小测试用例来比较YAML和JSON的速度: import json import yaml from datetime import datetime from random import randint NB_ROW=1024 print 'Does yaml is using libyaml ? ',yaml.__with_libyaml__ and 'yes' or 'no' dummy_data = [ { 'dummy_key_A_%s' % i: i, 'dummy

我制作了一个小测试用例来比较YAML和JSON的速度:

import json
import yaml
from datetime import datetime
from random import randint

NB_ROW=1024

print 'Does yaml is using libyaml ? ',yaml.__with_libyaml__ and 'yes' or 'no'

dummy_data = [ { 'dummy_key_A_%s' % i: i, 'dummy_key_B_%s' % i: i } for i in xrange(NB_ROW) ]


with open('perf_json_yaml.yaml','w') as fh:
    t1 = datetime.now()
    yaml.safe_dump(dummy_data, fh, encoding='utf-8', default_flow_style=False)
    t2 = datetime.now()
    dty = (t2 - t1).total_seconds()
    print 'Dumping %s row into a yaml file : %s' % (NB_ROW,dty)

with open('perf_json_yaml.json','w') as fh:
    t1 = datetime.now()
    json.dump(dummy_data,fh)
    t2 = datetime.now()
    dtj = (t2 - t1).total_seconds()
    print 'Dumping %s row into a json file : %s' % (NB_ROW,dtj)

print "json is %dx faster for dumping" % (dty/dtj)

with open('perf_json_yaml.yaml') as fh:
    t1 = datetime.now()
    data = yaml.safe_load(fh)
    t2 = datetime.now()
    dty = (t2 - t1).total_seconds()
    print 'Loading %s row from a yaml file : %s' % (NB_ROW,dty)

with open('perf_json_yaml.json') as fh:
    t1 = datetime.now()
    data = json.load(fh)
    t2 = datetime.now()
    dtj = (t2 - t1).total_seconds()
    print 'Loading %s row into from json file : %s' % (NB_ROW,dtj)

print "json is %dx faster for loading" % (dty/dtj)
结果是:

Does yaml is using libyaml ?  yes
Dumping 1024 row into a yaml file : 0.251139
Dumping 1024 row into a json file : 0.007725
json is 32x faster for dumping
Loading 1024 row from a yaml file : 0.401224
Loading 1024 row into from json file : 0.001793
json is 223x faster for loading
我在Ubuntu12.04上使用Pyyaml3.11和libyamlC库。 我知道json比yaml简单得多,但json和yaml的比例是223倍,我想知道我的配置是否正确

你们有相同的速比吗?

如何加快yaml.load()的速度?

您可能已经注意到Python的数据结构语法与JSON的语法非常相似

现在发生的事情是Python的
json
库对Python的内置数据类型进行编码,将
替换为
,并在这里和那里删除
(有点过于简化)

另一方面,
pyyaml
必须在将其序列化为字符串之前进行修改

加载时,同样的情况必须向后发生

加速
yaml.load()
的唯一方法是编写一个新的
Loader
,但我怀疑这可能是性能上的巨大飞跃,除非您愿意编写自己的单一用途的
yaml
解析器,同时考虑到:

YAML构建图形是因为它是一种通用序列化 能够表示对同一对象的多个引用的格式 对象。如果您知道没有对象重复,并且只显示基本类型, 您可以使用json序列化器,它仍然是有效的YAML

--更新

我之前所说的仍然正确,但是如果您正在运行
Linux
,有一种方法可以加速
Yaml
解析。默认情况下,Python的
Yaml
使用Python解析器。您必须告诉它您想要使用
PyYaml
C
解析器

您可以这样做:

import yaml
from yaml import CLoader as Loader, CDumper as Dumper

dump = yaml.dump(dummy_data, fh, encoding='utf-8', default_flow_style=False, Dumper=Dumper)
data = yaml.load(fh, Loader=Loader)
为此,您需要安装
yaml-cpp-dev
(软件包后来重命名为
libyaml-cpp-dev
),例如,安装apt-get:

$ apt-get install yaml-cpp-dev
还有
PyYaml
LibYaml
。但根据您的输出,情况已经是这样了


我现在无法测试它,因为我正在运行OS X,而且
brew
在安装
yaml cpp dev
时遇到了一些问题,但是如果您遵循,他们非常清楚性能会更好。

是的,我还注意到JSON要快得多。因此,合理的方法是首先将yaml转换为JSON。如果您不介意ruby,然后,您可以获得很大的加速,并完全放弃
yaml
安装:

import commands, json
def load_yaml_file(fn):
    ruby = "puts YAML.load_file('%s').to_json" % fn
    j = commands.getstatusoutput('ruby -ryaml -rjson -e "%s"' % ruby)
    return json.loads(j[1])
以下是100K记录的比较:

load_yaml_file: 0.95 s
yaml.load: 7.53 s
对于100万条记录:

load_yaml_file: 11.55 s
yaml.load: 77.08 s

如果您仍然坚持使用yaml.load,请记住将其放在virtualenv中,以避免与其他软件发生冲突。

作为参考,我比较了几种人类可读的格式,实际上Python的yaml阅读器是最慢的(请注意下图中的日志缩放)如果您想要速度,您需要一个JSON加载程序,例如:


复制绘图的代码:

导入numpy
导入性能图
导入json
导入ujson
导入orjson
导入toml
进口yaml
来自yaml导入加载程序,CLoader
进口大熊猫
def设置(n):
numpy.random.seed(0)
data=numpy.random.rand(n,3)
以开放(“out.yml”、“w”)作为f:
yaml.dump(data.tolist(),f)
以open(“out.json”,“w”)作为f:
json.dump(data.tolist(),f,indent=4)
以“out.dat”、“w”作为f:
savetxt(f,数据)
打开(“out.toml”、“w”)作为f:
toml.dump({“data”:data.tolist()},f)
def yaml_python(arr):
以open(“out.yml”、“r”)作为f:
out=yaml.load(f,Loader=Loader)
返回
def yaml_c(arr):
以open(“out.yml”、“r”)作为f:
out=yaml.load(f,Loader=CLoader)
返回
def json_加载(arr):
以open(“out.json”、“r”)作为f:
out=json.load(f)
返回
def ujson_加载(arr):
以open(“out.json”、“r”)作为f:
out=ujson.load(f)
返回
def或JSON_加载(arr):
以open(“out.json”、“rb”)作为f:
out=orjson.load(f.read())
返回
def loadtxt(arr):
以open(“out.dat”、“r”)作为f:
out=numpy.loadtxt(f)
返回
def_读取(arr):
out=pandas.read_csv(“out.dat”,header=None,sep=”“)
返回值
def toml_负载(arr):
以open(“out.toml”、“r”)作为f:
输出=总负载(f)
返回[“数据”]
perfplot.save(
“out.png”,
设置=设置,
果仁=[
yaml_python,
亚穆尔茨,
json_加载,
loadtxt,
你读到了吗,
toml_负载,
ujson_加载,
ORU加载,
],
n_范围=[2**k表示范围(18)中的k],
)

加载yayl的速度慢12X。我的示例是600000个空字典的列表。YAML不需要做任何额外的操作,只是稍微聪明的语法分析,几乎不需要额外的时间。在Mac:BREW安装YAML CPP LyByAMLJVIVE,您是一个血腥的传奇。我将重写C++中的一些Python代码来加快速度。使用标准yaml加载器加载我的6MB yaml文件花了53秒,而使用CLoader只花了3秒。我不知道为什么你说CLoader的加速只有在Linux下运行时才有意义;我只是在windows下尝试了一下,效果很好,给了我巨大的加速。如果你
无法从“yaml”导入名称“CLoader”
尝试安装
libyaml-dev
,然后重新安装pyyaml:
pip--no-cache-dir-install--verbose--force-reinstall-I pyyaml
我不介意ruby,但我介意伪造的答案。1)你不是真的在使用ruby,在你的代码中你使用的是:“底层实现是libyaml-wrapper-Psych“.2)将其与没有libyaml C库的PyYAML进行比较。如果有,您将看到Python包装libyaml的速度不是7倍,而是只有几个百分点。3) 2006年,PEP 0361发布了弃用
命令
模块的公告,您仍然建议在11年后使用该模块。