Программирование arrow Microsoft .NET arrow Оптимизация сериализации в .NET

Оптимизация сериализации в .NET

Оглавление

Приводятся код и методы, позволяющие разработчикам оптимизировать сериализацию данных.

Введение

Это первая из двух статей про оптимизацию сериализации, особенно для использования в удаленном взаимодействии.

Эта первая статья содержит универсальный код, который используется для сохранения 'принадлежащих данных' (определяются позже) в компактную структурную единицу с максимальной скоростью. Вторая статья приводит пример того, как использовать этот код для сериализации наборов данных как автономных блоков. Возможная третья статья расскажет, как сериализовать Entity и EntityCollections из LLBLGenPro - ведущей O/R программы управления памятью – как пример того, как использовать весь процесс сериализации для получения наилучших результатов. Хотя это написано для одного конкретного приложения, вы можете найти эти методы полезными и для своего кода.

Если вы использовали удаленное взаимодействие .NET для больших объемов данных, то наверняка обнаружили, что в нем есть проблемы с расширяемостью. Для небольших объемов данных оно работает достаточно хорошо, но большие объемы отнимают много ресурсов процессора и памяти, генерируют огромные объемы данных для передачи и могут привести к сбою из-за нехватки памяти. Также большой проблемой является время, требуемое для реального выполнения сериализации – большие объемы данных может быть нереально использовать в приложениях, независимо от затрат ресурсов процессора/памяти, просто потому что выполнение сериализации/десериализации отнимает очень много времени. Использование сжатия данных через приемники сервера и клиента может помочь уменьшить итоговый размер передаваемых данных, но не позволит устранить излишние объемы данных на более ранних этапах процесса.

Вы не можете винить в этом .NET, учитывая всю работу, которую она делает: она обеспечивает выявление целого графа объектов, требуемых для воссоздания исходного объекта, и многократные ссылки на один и тот же объект обрабатываются должным образом, чтобы обеспечить то, что только один общий экземпляр десериализуется. Она также вынуждена делать это через отражение, и  иметь возможность делать это без каких-либо априорных знаний о включенных объектах, так что в целом она выполняет довольно хорошую работу. Она также дает вам возможность принять участие в процессе сериализации/десериализации, позволяя вам реализовать интерфейс ISerializable, если вы знаете, как сделать что-то лучшее, чем просто восстановление эксплуатационных данных через отражение.

'Априорное знание' – это ключевой момент здесь. Его можно использовать для оптимизации сохранения определенных 'принадлежащих данных' (определяются позже), оставив всю остальную работу .NET. Это и есть предмет данной статьи.

Позвольте привести пример возможного масштаба оптимизации:

Имеется набор справочных данных из 34,423 строк в таблице базы данных, который был сохранен в виде коллекции объектов-сущностей. Ее сериализация (с помощью MemoryStream для максимальной скорости) занимает целые 92 секунды, и на выходе получается 13.5Мб сериализованных данных. Их десериализация отнимает примерно 58 секунд – не очень удобно для сценария удаленного взаимодействия!

Используя методы, описанные в данной статье, можно при сериализации тех же самых данных получить на выходе 2.1Мб, что отнимет всего 0.35 секунд на сериализацию и 0.82 секунды на десериализацию! Доля использования ресурсов процессора и памяти будет небольшой частью от тех, которые использует исходный сериализатор .NET.

Использование кода

Как указано во введении, загружаемый код достаточно универсален, поэтому в нем, по сути,  не содержится ничего специфического для удаленного взаимодействия. По существу, вы помещаете 'принадлежащие' данные в экземпляр класса SerializationWriter и затем используете метод ToArray, чтобы получить byte[],SerializationInfo,ISerializable.GetObjectData(), как обычно, таким образом: содержащий сериализованные данные. Затем его можно сохранить в параметре передаваемом методу

public virtual void GetObjectData(SerializationInfo info,
                                  StreamingContext context)
{
    SerializationWriter writer = new SerializationWriter();
    writer.Write(myInt32Field);
    writer.Write(myDateTimeField);
    writer.Write(myStringField);
    // и т.д.
    info.AddValue("data", writer.ToArray());
}

Десериализация, по существу, обратный процесс: в конструкторе десериализации вы извлекаете byte[] и создаете экземпляр SerializationReader, передавая byte[] его конструктору. Затем данные извлекаются в том самом же порядке, как они были записаны:

protected EntityBase2(SerializationInfo info, StreamingContext context)
{
    SerializationReader reader =
      new SerializationReader((byte[]) info.GetValue("data",
                               typeof(byte[])));
    myInt32Field = reader.ReadInt32();
    myDateTimeField = reader.ReadDateTime();
    myString = reader.ReadString();
    // и т.д.
}

Просто скопируйте файл FastSerializer.cs в ваш проект, измените пространство имен соответственно, и он будет готов к использованию. Прикрепленные к статье файлы также включают в себя файл FastSerializerTest.cs  с более чем 220 тестами, но в этом нет особой необходимости, и вам стоит его добавить только в том случае, если вы хотите изменить код с гарантией того, что ничего не будет испорчено.


 
Следующая статья »


  • .NET Framework, Плавающая точка в .NET - часть 1: принципы и форматы
    Данная статья представит основные принципы арифметических операций с плавающей точкой: числовые форматы, точности и достоверность, погрешности округления. Также в статью включено обсуждение типов плавающей запятой в .NET....
  • .NET Framework, JIT-оптимизации
    Компилятор .NET Just-In-Time Compiler (JIT) считается многими одним из основных преимуществ производительности CLR по сравнению с JVM и другими управляемыми средами, которые используют двоичный код, скомпилированный компилятором JIT. ...
  • .NET Framework, Инъекции CLR: замена методов во время выполнения
    Многие из нас, наверняка, были заинтересованы в том, как работает универсальный язык CLR. Одной из наиболее интересных вещей является динамический компилятор JIT (Just In Time Compiler). Мы рассмотрим то, как JIT компилирует MSIL и создадим утилиту, которая позволяет программным образом заменить любой метод (JIT) другим во время выполнения. Мы также создадим отладочную утилиту, которая прехватывает JIT-вызовы и выводит в консоль информацию о диагноcnbrt....
  • .NET Framework, Оптимизация запуска приложений .NET
    Ждать, пока приложение запустится, неприятно для многих пользователей, поэтому ускорение запуска приложений клиентов может значительно улучшить первое впечатление от вашей работы. И так как скорость запуска имеет значение, следует знать факторы, которые на нее влияют, чтобы избежать распространенных ошибок....
  • .NET Framework, Создание компилятора языка для .NET Framework
    Эксперты по компиляторам являются знаменитостями в компьютерном мире. Я видел, как Андерс Хейльсберг (Anders Hejlsberg) представлял презентацию на конференции разработчиков Professional Developers Conference и когда он сошел со сцены, его встретила целая орда мужчин и женщин, просящих поставить автограф на книгу, или сняться на фотографии вместе с ними. Люди, посвящающие свое время изучению и пониманию всех тонкостей лямбда-выражений, систем типов и языков сборки, кажутся своего рода носителями ...
  • .NET Framework, Маршалинг данных между управляемым и неуправляемым кодом
    Посмотрим правде в глаза: нет в мире совершенства. Мало кто при разработке использует только управляемый код. А между тем, тяжким грузом лежат устаревшие неуправляемые приложения, с которыми приходится мириться. Есть ли способ интегрировать проекты, в которых задействован как управляемый, так и неуправляемый код? Какой вид принимает этот способ: вызов неуправляемого кода из управляемого приложения или вызов управляемого кода из неуправляемого приложения?...
  • .NET Framework, IronPython как движок для макросов в .NET приложениях
    Подозреваю, многие из вас задумывались — как можно в .NET приложение добавить поддержку макросов — чтобы можно было расширять возможности программы без ее перекомпиляции и предоставить сторонним разработчикам возможность легко и просто получить доступ к API вашего приложения? В статье рассмотрено, как в качестве основы для выполнения макросов использовать IronPython — реализацию языка Python на платформе .NET....
  • .NET Framework, Xml сериализация в .Net Framework 2.0
    Xml широко используется в .Net приложениях, и .Net framework предоставляет богатые возможности по работе с Xml. Среди них: поддержка Xml DOM (System.Xml.XmlDocument), последовательное чтение - запись Xml, поддержка xPath и xQuery, поддержка XSLT, богатые возможности DataSet по работе с Xml и, наконец, Xml сериализация. ...