Как получается, что сериализация json намного быстрее, чем сериализация yaml в Python?

У меня есть код, который в значительной степени опирается на yaml для многоязыковой сериализации, и, работая над ускорением некоторых вещей, я заметил, что yaml был безумно медленным по сравнению с другими методами сериализации (например, pickle, json).

Итак, что действительно вызывает у меня в голове то, что json намного быстрее, чем yaml, когда результат почти идентичен.

>>> 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 CSafeDumper и cjson написаны на C, так что это не так, как проблема скорости C vs Python. Я даже добавил к нему некоторые случайные данные, чтобы узнать, делает ли cjson какое-либо кэширование, но все еще быстрее, чем PyYaml. Я понимаю, что yaml является надмножеством json, но как может быть, что последовательный сериал yaml на 2 порядка медленнее с таким простым вводом?

Ответ 1

В общем, это не сложность вывода, определяющая скорость разбора, а сложность принятого ввода. Грамматика JSON очень сжата. Анализаторы YAML сравнительно сложны, что приводит к увеличению накладных расходов.

Основная цель проекта JSON простота и универсальность. Таким образом, JSON тривиально, чтобы генерировать и анализировать, за счет сокращения человеческих читаемость. Он также использует общая информационная модель знаменателя, обеспечение любых данных JSON может быть легко обрабатывается каждым современным программированием окружающая среда.

В отличие от YAML, цели являются читабельность человека и поддержка сериализации произвольных собственные структуры данных. Таким образом, YAML позволяет читать чрезвычайно читаемые файлы, но сложнее генерировать и разобрать. Кроме того, YAML за пределами самого низкого общего знаменателя типы данных, требующие более сложных обработки при пересечении различные среды программирования.

Я не являюсь разработчиком парсеров YAML, поэтому я не могу говорить конкретно с порядком величины без каких-либо профилирующих данных и большого массива примеров. В любом случае, обязательно испытайте большой объем входных данных, прежде чем почувствовать уверенность в контрольных номерах.

Обновить. Упс, неправильно прочитайте вопрос.:-( Сериализация все еще может быть невероятно быстрой, несмотря на большую входную грамматику, однако, просматривая исходный код, похоже, что сериализация PyYAML на уровне Python создает граф представления тогда как simplejson кодирует встроенные типы данных Python непосредственно в текстовые фрагменты.

Ответ 2

В приложениях, над которыми я работал, вывод типа между строками в числа (float/int) - это то, где наибольшие издержки для разбора yaml связаны с тем, что строки могут быть записаны без кавычек. Поскольку все строки в json находятся в кавычках, при анализе строк нет возврата. Отличным примером, где это будет замедляться, является значение 0000000000000000000. Вы не можете сказать, что это значение является строкой, пока вы не прочитали ее до конца.

Другие ответы верны, но это конкретная деталь, которую я обнаружил на практике.

Ответ 3

Говоря об эффективности, я использовал YAML какое-то время и почувствовал привлекательность простоты, которую некоторые имена назначают на этом языке. Тем не менее, в этом процессе я так часто спотыкался об одной из ясности YAML, тонких вариациях в грамматике, которые позволяют писать специальные случаи в более сжатом стиле и т.д. В конце концов, хотя грамматика YAMLs почти определенно формально последовательна, она оставила меня с определенным чувством "неопределенности". Затем я ограничился тем, чтобы не трогать существующий, работающий код YAML и писать все новое в более кольцевом, отказоустойчивом синтаксисе, что заставило меня отказаться от всего YAML. В результате YAML пытается выглядеть как стандарт W3C и создает небольшую библиотеку трудночитаемой литературы, касающуюся ее концепций и правил.

Это, я считаю, гораздо более интеллектуальным, чем нужно. Посмотрите на SGML/XML: разработанный IBM в ревущих 60-х годах, стандартизованный ISO, известный (в заглушенном и измененном виде), как HTML, для бесчисленных миллионов людей, документированный и документированный и документированный снова во всем мире. Приходит маленький JSON и убивает этого дракона. Как JSON стал настолько широко использоваться за столь короткий промежуток времени, только с одним скудным сайтом (и подсветкой javascript для его поддержки)? Это в своей простоте, простое отсутствие сомнений в грамматике, простота обучения и использования.

XML и YAML трудны для людей, и они сложны для компьютеров. JSON довольно дружелюбен и прост для людей и компьютеров.

Ответ 4

Беглый взгляд на python-yaml предполагает, что его дизайн намного сложнее, чем cjson's:

>>> 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']

Более сложные конструкции почти всегда означают более медленные конструкции, и это намного сложнее, чем когда-либо потребуется большинству людей.