print - python json to dict
¿Cómo es que la serialización json es mucho más rápida que la serialización yaml en Python? (4)
Tengo un código que depende mucho de yaml para la serialización entre idiomas y mientras trabajaba en acelerar algunas cosas, noté que yaml era increíblemente lento en comparación con otros métodos de serialización (por ejemplo, pickle, json).
Entonces, lo que realmente me sorprende es que json es mucho más rápido que yaml cuando la salida es casi idéntica.
>>> import yaml, cjson; d={''foo'': {''bar'': 1}}
>>> yaml.dump(d, Dumper=yaml.SafeDumper)
''foo: {bar: 1}/n''
>>> cjson.encode(d)
''{"foo": {"bar": 1}}''
>>> import yaml, cjson;
>>> timeit("yaml.dump(d, Dumper=yaml.SafeDumper)", setup="import yaml; d={''foo'': {''bar'': 1}}", number=10000)
44.506911039352417
>>> timeit("yaml.dump(d, Dumper=yaml.CSafeDumper)", setup="import yaml; d={''foo'': {''bar'': 1}}", number=10000)
16.852826118469238
>>> timeit("cjson.encode(d)", setup="import cjson; d={''foo'': {''bar'': 1}}", number=10000)
0.073784112930297852
PyYaml''s CSafeDumper y cjson están escritos en C, por lo que no es un problema de velocidad de C contra Python. Incluso he agregado algunos datos aleatorios para ver si cjson está haciendo un caché, pero aún es mucho más rápido que PyYaml. Me doy cuenta de que yaml es un superconjunto de json, pero ¿cómo podría el serializador yaml ser 2 órdenes de magnitud más lento con tan simple entrada?
En aplicaciones en las que he trabajado, la inferencia de tipo entre cadenas a números (float / int) es donde se encuentra la mayor sobrecarga para analizar yaml, porque las cadenas se pueden escribir sin comillas. Como todas las cadenas en json están entre comillas, no hay retroceso al analizar cadenas. Un gran ejemplo en el que esto se ralentizaría es el valor 0000000000000000000s. No puede decir que este valor es una cadena hasta que haya leído hasta el final.
Las otras respuestas son correctas, pero este es un detalle específico que descubrí en la práctica.
En general, no es la complejidad del resultado lo que determina la velocidad de análisis, sino la complejidad de la entrada aceptada. La gramática JSON es muy concisa . Los analizadores YAML son comparativamente complejos , lo que genera un aumento de los gastos generales.
El principal objetivo de diseño de JSON es la simplicidad y la universalidad. Por lo tanto, JSON es trivial para generar y analizar, a costa de reducir la legibilidad humana. También utiliza un modelo de información de denominador común más bajo, asegurando que cualquier información JSON pueda ser procesada fácilmente por cada entorno de programación moderno.
En contraste, los principales objetivos de diseño de YAML son la legibilidad humana y el soporte para la serialización de estructuras de datos nativas arbitrarias. Por lo tanto, YAML permite archivos extremadamente legibles, pero es más complejo de generar y analizar. Además, YAML se aventura más allá de los tipos de datos de denominador común más bajo, lo que requiere un procesamiento más complejo al cruzar entre diferentes entornos de programación.
No soy un implementador de analizador de YAML, por lo que no puedo hablar específicamente de órdenes de magnitud sin algunos datos de perfil y un gran corpus de ejemplos. En cualquier caso, asegúrese de probar un gran conjunto de entradas antes de sentirse confiado en los números de referencia.
Actualiza Whoops, leyó mal la pregunta. :-( La serialización aún puede ser tremendamente rápida a pesar de la gran gramática de entrada, sin embargo, al explorar la fuente, parece que la serialización Python de PyYAML construye un gráfico de representación mientras que simplejson codifica los tipos de datos incorporados de Python directamente en fragmentos de texto.
Hablando de eficiencia, utilicé YAML por un tiempo y me sentí atraído por la simplicidad que algunas asignaciones de nombre / valor adquieren en este lenguaje. Sin embargo, durante el proceso tropecé con una de las fintas de YAML, variaciones sutiles en la gramática que te permiten escribir casos especiales en un estilo más conciso y demás. Al final, aunque la gramática de YAML es casi con certeza formalmente consistente, me ha dejado una cierta sensación de ''vaguedad''. Luego me limité a no tocar el código YAML existente y de trabajo, y escribir todo lo nuevo en una sintaxis más redundante y segura, lo que me hizo abandonar todo YAML. El resultado es que YAML intenta parecerse a un estándar W3C, y produce una pequeña biblioteca de literatura difícil de leer sobre sus conceptos y reglas.
Esto, creo, es mucho más intelectual de lo necesario. Mire SGML / XML: desarrollado por IBM en los años 60, estandarizado por el ISO, conocido (en una forma simplificada y modificada) como HTML para incontables millones de personas, documentado y documentado y documentado de nuevo en todo el mundo. Llega el pequeño JSON y mata a ese dragón. ¿Cómo podría JSON llegar a ser tan ampliamente utilizado en tan poco tiempo, con solo un sitio web exiguo (y una luminaria de JavaScript para respaldarlo)? Es en su simplicidad, la pura ausencia de dudas en su gramática, la facilidad de aprender y usarla.
XML y YAML son difíciles para los humanos, y son difíciles para las computadoras. JSON es bastante amigable y fácil para los humanos y las computadoras.
Una mirada superficial a python-yaml sugiere que su diseño es mucho más complejo que el de cjson:
>>> dir(cjson)
[''DecodeError'', ''EncodeError'', ''Error'', ''__doc__'', ''__file__'', ''__name__'', ''__package__'',
''__version__'', ''decode'', ''encode'']
>>> dir(yaml)
[''AliasEvent'', ''AliasToken'', ''AnchorToken'', ''BaseDumper'', ''BaseLoader'', ''BlockEndToken'',
''BlockEntryToken'', ''BlockMappingStartToken'', ''BlockSequenceStartToken'', ''CBaseDumper'',
''CBaseLoader'', ''CDumper'', ''CLoader'', ''CSafeDumper'', ''CSafeLoader'', ''CollectionEndEvent'',
''CollectionNode'', ''CollectionStartEvent'', ''DirectiveToken'', ''DocumentEndEvent'', ''DocumentEndToken'',
''DocumentStartEvent'', ''DocumentStartToken'', ''Dumper'', ''Event'', ''FlowEntryToken'',
''FlowMappingEndToken'', ''FlowMappingStartToken'', ''FlowSequenceEndToken'', ''FlowSequenceStartToken'',
''KeyToken'', ''Loader'', ''MappingEndEvent'', ''MappingNode'', ''MappingStartEvent'', ''Mark'',
''MarkedYAMLError'', ''Node'', ''NodeEvent'', ''SafeDumper'', ''SafeLoader'', ''ScalarEvent'',
''ScalarNode'', ''ScalarToken'', ''SequenceEndEvent'', ''SequenceNode'', ''SequenceStartEvent'',
''StreamEndEvent'', ''StreamEndToken'', ''StreamStartEvent'', ''StreamStartToken'', ''TagToken'',
''Token'', ''ValueToken'', ''YAMLError'', ''YAMLObject'', ''YAMLObjectMetaclass'', ''__builtins__'',
''__doc__'', ''__file__'', ''__name__'', ''__package__'', ''__path__'', ''__version__'', ''__with_libyaml__'',
''add_constructor'', ''add_implicit_resolver'', ''add_multi_constructor'', ''add_multi_representer'',
''add_path_resolver'', ''add_representer'', ''compose'', ''compose_all'', ''composer'', ''constructor'',
''cyaml'', ''dump'', ''dump_all'', ''dumper'', ''emit'', ''emitter'', ''error'', ''events'', ''load'',
''load_all'', ''loader'', ''nodes'', ''parse'', ''parser'', ''reader'', ''representer'', ''resolver'',
''safe_dump'', ''safe_dump_all'', ''safe_load'', ''safe_load_all'', ''scan'', ''scanner'', ''serialize'',
''serialize_all'', ''serializer'', ''tokens'']
Los diseños más complejos casi invariablemente significan diseños más lentos, y esto es mucho más complejo de lo que la mayoría de la gente necesitará.