В повседневных задачах есть множество инструментов для работы с различными форматами данных, такими как JSON, TOML, YAML и другими.
msgspec
— это инструмент, который может работать со всеми этими форматами и при этом быть быстрым и простым в использовании. Для всех форматов один импорт, что в рамках работы с данной библиотекой является преимуществом. Если вам необходимо парсить много разных форматов данных, то эта библиотека точно подойдет вам.
Библиотека содержит:
Высокопроизводительные кодеры/декодеры для распространенных протоколов: JSON, MessagePack, YAML и TOMI.
Поддержка большого количества типов данных.
Быстрая валидация данных
Структуры, позволяющие представлять данные (похожие на attrs/pydantic, но работают быстрее)
Для начала установим библиотеку:
pip3 install "msgspec[toml,yaml]"
Без дополнительных параметров библиотека установится с поддержкой json и messagepack.
Сериализация / десериализация
Для сериализации и десериализации данных нужен формат данных и входное значение.
import msgspec
a = {"1": 2, "3": 4}
encoded_json_data = msgspec.json.encode(a)
print(encoded_json_data) # b'{"1": 2, "3": 4}'
decoded_data = msgspec.json.decode(encoded_json_data)
print(decoded_data) # {'1': 2, '3': 4}
yaml_data = msgspec.yaml.encode(a)
print(yaml_data) # b"'1': 2\n'3': 4\n"
Можно сделать вывод, что достаточно написать msgspec.{format}.[encode/decode]
, где format это json
, yaml
, toml
, msgpack
.
Валидация
Для валидации данных предлагается создавать классы, наследуясь от msgspec.Struct
, аналогичные как в attrs/dataclsses/pydantic.
class User(msgspec.Struct):
name: str
surname: str
email: str | None = None
print(msgspec.json.decode(b'{"name":"vasya","surname":"pupkin"}', type=User))
# User(name='vasya', surname='pupkin', email=None)
print(msgspec.json.decode(b'{"name":"vasya","surname":123}', type=User))
# print(msgspec.json.decode(b'{"name":"vasya","surname":123}', type=User))
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
# msgspec.ValidationError: Expected `str`, got `int` - at `$.surname`
Добавляется только аргумент type
, который определяет схему.
Бенчмарки
Сравним msgspec по скорости с самыми популярными библиотеками сериализации:
Для этого берем большие файлы и для каждого кейса прогоняем тысячу раз, сравниваем среднее время
Входные данные
tests = [
# JSON
{
"msgspec.json.decode(data)": {"data": json_text},
"json.loads(data)": {"data": json_text},
},
{
"msgspec.json.encode(data)": {"data": json_data},
"json.dumps(data)": {"data": json_data},
},
{
"msgspec.json.decode(data)": {"data": json_text},
"orjson.loads(data)": {"data": json_text},
},
{
"msgspec.json.encode(data)": {"data": json_data},
"orjson.dumps(data)": {"data": json_data},
},
# TOML
{
"msgspec.toml.decode(data)": {"data": toml_text},
"toml.loads(data)": {"data": toml_text},
},
{
"msgspec.toml.decode(data)": {"data": toml_text},
"tomllib.loads(data)": {"data": toml_text},
},
{
"msgspec.toml.encode(data)": {"data": toml_data},
"toml.dumps(data)": {"data": toml_data},
},
# YAML
{
"msgspec.yaml.decode(data)": {"data": yaml_text},
"yaml.load(data, Loader=yaml.Loader)": {
"data": yaml_text,
},
},
{
"msgspec.yaml.decode(data)": {"data": yaml_text},
"yaml.load(data, Loader=yaml.CLoader)": {
"data": yaml_text,
},
},
{
"msgspec.yaml.encode(data)": {"data": yaml_data},
"yaml.dump(data, Dumper=yaml.Dumper)": {
"data": yaml_data,
},
},
{
"msgspec.yaml.encode(data)": {"data": yaml_data},
"yaml.dump(data, Dumper=yaml.CDumper)": {
"data": yaml_data,
},
},
]
Тест |
Время (мс) |
Msgspec (мс) |
Ускорение |
json.loads(data) |
707.8 |
315.4 |
2.2 |
json.dumps(data) |
946.4 |
118.6 |
8.0 |
orjson.loads(data) |
306.2 |
315.7 |
1.0 |
orjson.dumps(data) |
83.9 |
118.2 |
0.7 |
toml.loads(data) |
1,017.9 |
420.0 |
2.4 |
tomllib.loads(data) |
420.4 |
420.2 |
1.0 |
toml.dumps(data) |
154.0 |
170.3 |
0.9 |
yaml.load(data, Loader=yaml.Loader) |
16,142.7 |
1,602.5 |
10.1 |
yaml.load(data, Loader=yaml.CLoader) |
1,625.4 |
1,603.1 |
1.0 |
yaml.dump(data, Dumper=yaml.Dumper) |
10,032.0 |
1,595.4 |
6.3 |
yaml.dump(data, Dumper=yaml.CDumper) |
1,600.5 |
1,594.8 |
1.0 |
Можно сделать вывод, что под капотом у библиотеки лучшие парсеры. Если вы пользуетесь только json, то стоит присмотреться к другой библиотеке (например, orjson), но все же значения библиотек не сильно критично разнятся. Также на примере yaml msgspec использует стандартные C имплементации.
Кроме того, есть бенчмарки от создателей библиотеки, которые сравнивают скорость сериализации и валидации данных.
Если в вашем коде требуется работа с различными форматами данных, например ваша программа принимает конфиг в yaml, поднимает API, которое отдаёт json и при этом не завязана на какой-нибудь pydantiс, то вам стоит попробовать msgspec. Также у библиотеки есть плюшки в виде json схем.
Комментарии (5)
Andrey_Solomatin
20.07.2024 15:40С YAML бывают проблемы из-за неполной поддержки части стандартов. Последняя версия формата либо не поддерживается, либо не полно поддерживается. Какой стандарт используется в статье?
Ryav
Почему нет сравнения с Pydantic v2?
Andrey_Solomatin
Может не хотят портить статистику?
9982th
На официальном сайте есть сравнение по скорости
По функциональности совпадение достаточно большое, но не стопроцентное.
Dominux
Pydantic не слабо рассчитан и на валидацию, так что сравнение не совсем честное