msgspec. Библиотека для сериализации и десериализации чего угодно
В повседневных задачах есть множество инструментов для работы с различными форматами данных, такими как 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 схем.