Хотя у вас есть принятый ответ, к сожалению, это только делает
некоторые рукопожатия в направлении документации PyYAML и
цитирует утверждение в этой документации, которое является неправильным: PyYAML
не создает граф представления во время дампа, он создает
Lineair Stream (и, как и json
, хранит список идентификаторов, чтобы увидеть, есть ли
рекурсии).
Прежде всего, вы должны понимать, что в то время как cjson
самосвал
Только C-код, созданный вручную, CSafeDumper YAML разделяет два из четырех этапов дампа
(Representer
и Resolver
) с обычным чистым Python SafeDumper
и что другие две стадии (Сериализатор и Эмиттер) не являются
написанный полностью вручную на C, но состоит из модуля Cython
который вызывает библиотеку C libyaml
для излучения.
Помимо этой важной части, простой ответ на ваш вопрос
почему это занимает больше времени, является то, что сброс YAML делает больше. Это не так
во многом потому, что YAML сложнее, как утверждает @flow, а потому, что
что делает YAML, делает его гораздо более мощным, чем JSON, а также
удобный для пользователя, если вам нужно обработать результат с помощью редактора. Тот
означает, что больше времени тратится в библиотеке YAML даже при применении этих дополнительных функций,
и во многих случаях также просто проверяет, применимо ли что-либо.
Вот пример: даже если вы никогда не проходили PyYAML
код, вы заметили, что дампер не цитирует foo
и
bar
. Это не потому, что эти строки являются ключами, как YAML не
есть ограничение, которое имеет JSON, что ключ для отображения должен
быть строкой. Например. строка Python, которая является значением в отображении , может
также не цитируемый (то есть простой).
Акцент на может , потому что это не всегда так. Принимать за
экземпляр строки, состоящей только из цифровых символов:
12345678
. Это должно быть записано в кавычках, иначе это
будет выглядеть точно так же, как число (и будет считываться как таковой при разборе).
Как PyYAML знает, когда заключать в кавычки строку, а когда нет? На сброс
на самом деле сначала дамп строки, затем анализирует результат, чтобы сделать
уверен, что когда он читает этот результат обратно, он получает исходное значение.
И если это не так, то применяются кавычки.
Позвольте мне повторить важную часть предыдущего предложения снова, поэтому
Вам не нужно перечитывать это:
выводит строку, затем анализирует результат
Это означает, что он применяет все регулярные выражения, соответствующие
загрузка, чтобы увидеть, будет ли полученный скаляр загружаться как целое число,
float, boolean, datetime и т. д., чтобы определить, должны ли быть кавычки
применяется или нет.
В любом реальном приложении со сложными данными на основе JSON
самосвал / загрузчик слишком прост для непосредственного использования и многое другое
интеллект должен быть в вашей программе по сравнению с тем же дампом
сложные данные непосредственно в YAML. Упрощенный пример, когда вы хотите работать
с отметками даты и времени, в этом случае вы должны преобразовать строку обратно
и далее datetime.datetime
, если вы используете JSON. Во время загрузки
Вы должны сделать это либо на основе того факта, что это значение
связанный с каким-то (можно надеяться, узнаваемым) ключом:
{ "datetime": "2018-09-03 12:34:56" }
или с позицией в списке:
["FirstName", "Lastname", "1991-09-12 08:45:00"]
или в зависимости от формата строки (например, с помощью регулярного выражения).
Во всех этих случаях в вашей программе необходимо выполнить гораздо больше работы. Такой же
держит для сброса, и это не только означает дополнительное время разработки.
Позволяет восстановить ваши тайминги с тем, что я получаю на моей машине
поэтому мы можем сравнить их с другими измерениями. Я переписал твой код
в некоторой степени, потому что он был неполным (timeit
?) и импортирован другим
вещи дважды. Также было невозможно просто вырезать и вставить из-за подсказок >>>
.
from __future__ import print_function
import sys
import yaml
import cjson
from timeit import timeit
NR=10000
ds = "; d={'foo': {'bar': 1}}"
d = {'foo': {'bar': 1}}
print('yaml.SafeDumper:', end=' ')
yaml.dump(d, sys.stdout, Dumper=yaml.SafeDumper)
print('cjson.encode: ', cjson.encode(d))
print()
res = timeit("yaml.dump(d, Dumper=yaml.SafeDumper)", setup="import yaml"+ds, number=NR)
print('yaml.SafeDumper ', res)
res = timeit("yaml.dump(d, Dumper=yaml.CSafeDumper)", setup="import yaml"+ds, number=NR)
print('yaml.CSafeDumper', res)
res = timeit("cjson.encode(d)", setup="import cjson"+ds, number=NR)
print('cjson.encode ', res)
и это выводит:
yaml.SafeDumper: foo: {bar: 1}
cjson.encode: {"foo": {"bar": 1}}
yaml.SafeDumper 3.06794905663
yaml.CSafeDumper 0.781533956528
cjson.encode 0.0133550167084
Теперь давайте
вывести простую структуру данных, которая включает datetime
import datetime
from collections import Mapping, Sequence # python 2.7 has no .abc
d = {'foo': {'bar': datetime.datetime(1991, 9, 12, 8, 45, 0)}}
def stringify(x, key=None):
# key parameter can be used to dump
if isinstance(x, str):
return x
if isinstance(x, Mapping):
res = {}
for k, v in x.items():
res[stringify(k, key=True)] = stringify(v) #
return res
if isinstance(x, Sequence):
res = [stringify(k) for k in x]
if key:
res = repr(res)
return res
if isinstance(x, datetime.datetime):
return x.isoformat(sep=' ')
return repr(x)
print('yaml.CSafeDumper:', end=' ')
yaml.dump(d, sys.stdout, Dumper=yaml.CSafeDumper)
print('cjson.encode: ', cjson.encode(stringify(d)))
print()
Это дает:
yaml.CSafeDumper: foo: {bar: '1991-09-12 08:45:00'}
cjson.encode: {"foo": {"bar": "1991-09-12 08:45:00"}}
Для синхронизации вышеперечисленного я создал модуль myjson, который оборачивает
cjson.encode
и имеет вышеуказанное значение stringify
. Если вы используете это:
d = {'foo': {'bar': datetime.datetime(1991, 9, 12, 8, 45, 0)}}
ds = 'import datetime, myjson, yaml; d=' + repr(d)
res = timeit("yaml.dump(d, Dumper=yaml.CSafeDumper)", setup=ds, number=NR)
print('yaml.CSafeDumper', res)
res = timeit("myjson.encode(d)", setup=ds, number=NR)
print('cjson.encode ', res)
дает:
yaml.CSafeDumper 0.813436031342
cjson.encode 0.151570081711
Этот довольно простой вывод уже возвращает вас из двух заказов
разница в скорости менее чем на один порядок.
Простые скаляры YAML и форматирование блочного стиля обеспечивают лучшую читаемость данных.
То, что вы можете иметь запятую в последовательности (или отображении), делает для
меньше ошибок при ручном редактировании данных YAML, как с теми же данными в JSON.
Теги YAML позволяют в ваших данных указывать ваши (сложные) типы. когда
используя JSON , вы должны позаботиться в своем коде о чем-либо еще
сложнее, чем отображения, последовательности, целые числа, числа с плавающей запятой, логические и
строки. Такой код требует времени разработки и вряд ли будет
так быстро, как python-cjson
(вы, конечно, можете написать свой код
в Си.
Вывод некоторых данных, таких как рекурсивные структуры данных (например, топологические
данные) или сложные ключи предварительно определены в библиотеке PyYAML. Там
Библиотека JSON просто выдает ошибки и реализует обходной путь для этого
нетривиально и, скорее всего, замедляет то, что различия в скорости менее актуальны.
Такая мощность и гибкость достигается за счет более низкой скорости. когда
выбрасывать много простых вещей JSON - лучший выбор, вы вряд ли
в любом случае собираюсь редактировать результат вручную. Для любого, что включает
редактирование или сложные объекты или оба, вы все равно должны рассмотреть возможность использования
YAML.
¹ Можно принудительно сбросить все строки Python как YAML
скаляры с (двойными) кавычками, но установки стиля недостаточно для
запретить обратное чтение.