Сериализация буфера протокола Google зависает при записи данных объемом 1 ГБ + - PullRequest
7 голосов
/ 15 июня 2011

Я сериализирую большой набор данных, используя сериализацию буфера протокола.Когда мой набор данных содержит 400000 пользовательских объектов объединенного размера около 1 ГБ, сериализация возвращается через 3 ~ 4 секунды.Но когда мой набор данных содержит 450000 объектов объединенного размера около 1,2 ГБ, вызов сериализации никогда не возвращается и процессор постоянно потребляется.

Я использую порт .NET для буферов протокола.

Ответы [ 2 ]

7 голосов
/ 20 июня 2011

Глядя на новые комментарии, представляется, что (как отмечает ОП) MemoryStream емкость ограничена.Небольшое раздражение в спецификации protobuf состоит в том, что, поскольку длины под-сообщений являются переменными и должны префикс под-сообщения, часто необходимо буферизовать части, пока длина не станет известной.Это хорошо для большинства разумных графов, но если есть исключительно большой граф (за исключением сценария «у корневого объекта есть миллионы прямых дочерних элементов», который не страдает), он может в конечном итоге сделать немного памяти.

Если вы не привязаны к определенному макету (возможно, из-за взаимодействия .proto с существующим клиентом), тогда простое исправление заключается в следующем: для дочерних (подобъектов) свойств(включая списки / массивы подобъектов), скажите ему использовать сериализацию "группы".Это не макет по умолчанию, но он говорит: "вместо использования префикса длины используйте пару токенов начала / конца".Недостатком этого является то, что , если ваш код десериализации не знает о конкретном объекте, требуется больше времени, чтобы пропустить поле, поскольку он не может просто сказать «искать вперед» 231413байты "- вместо этого он должен пройти токены, чтобы узнать, когда объект закончен.В большинстве случаев вообще не является проблемой , поскольку ваш код десериализации полностью ожидает эти данные.

Для этого:

[ProtoMember(1, DataFormat = DataFormat.Group)]
public SomeType SomeChild { get; set; }
....
[ProtoMember(4, DataFormat = DataFormat.Group)]
public List<SomeOtherType> SomeChildren { get { return someChildren; } }

Десериализация в protobuf-net очень простителен (по умолчанию есть необязательный строгий режим), и он с радостью десериализует группы вместо префикса длины и префикса длины вместо групп (то есть: любые данные, которые вы где-то уже сохранили, должны работать нормально).

1 голос
/ 15 июня 2011

1,2 ГБ памяти опасно близко к пределу управляемой памяти для 32-разрядных процессов .Net.Я предполагаю, что сериализация запускает OutOfMemoryException, и все адские разрывы ослабевают.

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

CheersФлориан

...