Сериализация данных
84C# и .NET Framework --- Оптимизация приложений .NET Framework --- Сериализация данных
Сериализация (serialization) - это операция преобразования объекта в формат, пригодный для записи на диск или отправки в сеть. Десериализация (deserialization) - это операция восстановления объекта из сериализованного представления. Например, хеш-таблица может быть сериализована в массив записей ключ/значение.
Тестирование производительности средств сериализации
В состав .NET Framework входит несколько универсальных средств сериализации, с помощью которых можно выполнять сериализацию и десериализацию пользовательских типов. В этом разделе оцениваются достоинства и недостатки каждого из них и приводятся результаты тестирования производительности и компактности получаемых данных.
Для начала познакомимся с имеющимися средствами сериализации:
- XmlSerializer из пространства имен System.Xml.Serialization
-
сериализует текстовые и двоичные данные в формат XML;
сериализует дочерние объекты, но не поддерживает циклические ссылки;
сериализует только общедоступные поля и свойства, за исключением тех, что явно исключены из сериализации;
для повышения эффективности использует механизм рефлексии (Reflection) только единожды, когда генерирует код сборки сериализации, - для предварительного создания сборки сериализации можно использовать инструмент sgen.exe;
позволяет настраивать схему XML;
требует знания всех типов, участвующих в сериализации: эта информация выводится автоматически, за исключением случаев, когда используются унаследованные типы.
- BinaryFormatter из пространства имен System.Runtime.Serialization.Formatters.Binary
-
сериализует в закрытый двоичный формат, который распознается только классом BinaryFormatter;
используется механизмом .NET Remoting, но может использоваться как самостоятельный инструмент сериализации;
сериализует не только общедоступные поля;
распознает циклические ссылки;
не требует предварительного знания типов сериализуемых объектов;
определения сериализуемых типов должны быть отмечены атрибутом [Serializable].
- SoapFormatter из пространства имен System.Runtime.Serialization.Formatters.Soap
-
своими возможностями напоминает BinaryFormatter, но сериализует в формат SOAP XML, более пригодный для обмена данными с другими системами, но менее компактный;
не поддерживает обобщенные типы и обобщенные коллекции и, соответственно, не рекомендуется к использованию в последних версиях .NET Framework.
- DataContractSerializer из пространства имен System.Runtime.Serialization
-
сериализует текстовые и двоичные данные в формат XML;
используется механизмом WCF, но может использоваться как самостоятельный инструмент сериализации;
сериализует типы и поля, отмеченные атрибутами [DataContract] и [DataMember]: если класс отмечен атрибутом [Serializable], сериализоваться будут все поля этого класса;
требует знания всех типов, участвующих в сериализации: эта информация выводится автоматически, за исключением случаев, когда используются унаследованные типы;
- NetDataContractSerializer из пространства имен System.Runtime.Serializatio
-
напоминает DataContractSerializer, но встраивает в сериализованные данные информацию о типе;
не требует предварительного знания типов сериализуемых объектов;
требует доступа к сборкам, содержащим объявления сериализуемых типов.
- DataContractJsonSerializer из пространства имен System.Runtime.Serialization
-
напоминает DataContractSerializer, но сериализует в формат JSON вместо XML.
На рисунке ниже представлены результаты тестирования производительности средств сериализации, описанных выше. Некоторые из них тестировались дважды - для сериализации в текстовый и двоичный формат. В ходе тестирования выполнялась сериализация и десериализация очень сложного графа объектов, включающего 3600 экземпляров пяти типов и имеющего древовидную структуру. Каждый тип имел поля типов string и double, а также массивы элементов этих типов. Циклические ссылки отсутствовали в тестовом наборе данных, потому что не все средства сериализации поддерживают их; однако те, что поддерживают их, обрабатывали данные существенно медленнее при их наличии.

Результаты тестирования, представленные здесь, были получены в версии .NET Framework 4.5 RC, показывающей немного более высокую производительность в сравнении с версией .NET Framework 3.5 в тестах сериализации в двоичный формат XML, но в остальных тестах производительность практически ничем не отличалась.
Из результатов тестирования можно заключить, что самыми быстрыми являются DataContractSerializer и XmlSerializer, при сериализации в двоичный формат XML.
Затем мы сравнили эти же средства по объему данных, полученных в результате сериализации (показано на рисунке ниже). Здесь можно выделить несколько инструментов, очень близких по этому показателю. Скорее всего это обусловлено тем, что наибольший объем данных был сосредоточен в строках, которые сериализуются в одно и то же представление всеми описываемыми средствами.

Наиболее компактное представление сериализованных данных дает DataContractJsonSerializer. За ним близко следуют XmlSerializer и DataContractSerializer, при сериализации в двоичный формат. Самое удивительное, пожалуй, что класс BinaryFormatter был превзойден по производительности большинством других средств сериализации.
Сериализация объектов DataSet
Объект DataSet - это кеш в памяти для хранения данных, извлеченных из базы данных с помощью DataAdapter. Он содержит коллекцию объектов DataTable, определяющую структуру базы данных и записи с данными, каждая из которых содержит коллекцию сериализованных объектов. Объекты DataSet чрезвычайно сложны, занимают большие объемы памяти, и требуют значительных вычислительных затрат на сериализацию. Однако многие приложения передают их между своими уровнями.
Ниже приводится несколько советов, следование которым поможет уменьшить накладные расходы, связанные с сериализацией DataSet:
Вызывайте метод DataSet.ApplyChanges() перед сериализацией DataSet. Объекты DataSet хранят оригинальные и измененные значения. Если вам не требуется сериализовать старые значения, вызывайте ApplyChanges(), чтобы отбросить их.
Сериализуйте только те объекты DataTables, которые действительно необходимы. Если DataSet содержит ненужные вам таблицы, подумайте о возможности скопировать нужные таблицы в новый объект DataSet и сериализовать его.
Используйте вместо имен столбцов более короткие псевдонимы (с помощью ключевого слова as), чтобы уменьшить объем сериализованных данных. Например, взгляните на следующую инструкцию SQL:
SELECT EmployeeID As I, Name As N, Age As A