Эффективное создание Python dict из десериализованного сообщения protobufPython

Программы на Python
Anonymous
Эффективное создание Python dict из десериализованного сообщения protobuf

Сообщение Anonymous »

Я хочу сравнить производительность некоторых альтернатив json в Python. Я провел тест следующим образом, сравнивая библиотеку stanadrd json с orjson и protobuf.

Код: Выделить всё

import orjson
import json
import time
import sys
import message_pb2
from google.protobuf.internal import api_implementation
from google.protobuf.json_format import MessageToDict
print(f"This should be 'upb': {api_implementation.Type()=}\n")

message = message_pb2.ChatMessage()
parsed_message = message_pb2.ChatMessage()

message.sender = "Test Name"
message.active_connections = 40
message.memory_usage = 0.554781258874
message.data.extend(["Hammer", "Radio"])

x = {
"name": "Test Name",
"age": 40,
"random_float": 0.554781258874,
"items": ["Hammer", "Radio"]
}

NUM_TESTS = 1000000

def perf_tests():
# Protobuf
t0 = time.perf_counter()
for _ in range(NUM_TESTS):
binary_data = message.SerializeToString()
t1 = time.perf_counter()
proto_serialize_time = (t1 - t0)*1000
print(f"\nProtobuf serialize:   {proto_serialize_time:,.0f} ms")

for _ in range(NUM_TESTS):
parsed_message.ParseFromString(binary_data)
t2 = time.perf_counter()
proto_deserialize_time = (t2 - t1)*1000
print(f"Protobuf deserialize: {proto_deserialize_time:,.0f} ms")
print(f"Protobuf total:       {proto_serialize_time + proto_deserialize_time:,.0f} ms")
print(f"Protobuf file size:   {sys.getsizeof(binary_data)} b")

# Orjson
t0 = time.perf_counter()
for _ in range(NUM_TESTS):
x_dump = orjson.dumps(x)
t1 = time.perf_counter()
orjson_serialize_time = (t1 - t0)*1000
print(f"\nOrjson serialize:     {orjson_serialize_time:,.0f} ms")

for _ in range(NUM_TESTS):
x_1 = orjson.loads(x_dump)
t2 = time.perf_counter()
orjson_deserialize_time = (t2 - t1)*1000
print(f"Orjson deserialize:   {orjson_deserialize_time:,.0f} ms")
print(f"Orjson total:         {orjson_serialize_time + orjson_deserialize_time:,.0f} ms")
print(f"Orjson file size:     {sys.getsizeof(x_dump)} b")

# Json
t0 = time.perf_counter()
for _ in range(NUM_TESTS):
x_dump = json.dumps(x)
t1 = time.perf_counter()
json_serialize_time = (t1 - t0)*1000
print(f"\nJson serialize:       {json_serialize_time:,.0f} ms")

for _ in range(NUM_TESTS):
x_1 = json.loads(x_dump)
t2 = time.perf_counter()
json_deserialize_time = (t2 - t1)*1000
print(f"Json deserialize:     {json_deserialize_time:,.0f} ms")
print(f"Json total:           {json_serialize_time + json_deserialize_time:,.0f} ms")
print(f"Json file size:       {sys.getsizeof(x_dump)} b")

if __name__ == "__main__":
perf_tests()

Когда я запускаю такой тест, я получаю следующие результаты:

Код: Выделить всё

Protobuf serialize:   403 ms
Protobuf deserialize: 344 ms
Protobuf total:       747 ms
Protobuf file size:   64 b

Orjson serialize:     407 ms
Orjson deserialize:   645 ms
Orjson total:         1,052 ms
Orjson file size:     116 b

Json serialize:       3,588 ms
Json deserialize:     2,630 ms
Json total:           6,219 ms
Json file size:       132 b
Все, как и ожидалось: стандартная библиотека json самая медленная, orjson немного медленнее, чем protobug, а protobuf также имеет гораздо меньший размер файла.
Однако десериализованные данные то, что я получаю, по-прежнему является типом сообщения protobuf. Любая попытка преобразовать его в словарь абсолютно разрушает производительность. Использование MessageToDict увеличивает время десериализации с 344 мс до примерно 12 000 мс, что хуже, чем в стандартной библиотеке json.
Создание словаря вручную с использованием атрибутов объекта сообщения все равно увеличивает время десериализации примерно до 1000 мс, поэтому он снова проигрывает orjson.

Код: Выделить всё

x_dict = {
"name": parsed_message.sender,
"age": parsed_message.active_connections,
"random_float": parsed_message.memory_usage,
"items": parsed_message.data,
}
В сообщениях моего приложения есть несколько необязательных полей, поэтому мне пришлось бы создать несколько разных разработчиков словарей вручную, что было бы не идеально. Мне нравится уменьшение размера файла, но я удивлен, что не существует лучшего и более производительного способа сделать это, если я что-то упускаю?


Подробнее здесь: https://stackoverflow.com/questions/790 ... ed-message

Вернуться в «Python»