Информационные технологииStfw.Ru 🔍

.NET vs. Java

Олег Ремизов
🕛 04.07.2006, 15:14
Что бы там ни говорили, но сегодняшний мир вычислений ориентирован в основном на сетевые приложения. В основе этих приложений лежит модифицированная архитектура клиент-сервер - так называемая трехуровневая архитектура. Отличительная ее черта - наличие на стороне сервера приложения, которое, собственно, и реализует бизнес-логику в среде сервера приложений. Приложение взаимодействует с сервером баз данных с одной стороны и с удаленной клиентской частью, которая обычно выполняется в среде веб-браузера или приложения с GUI-интерфейсом.

Распространение трехуровневой архитектуры повлекло за собой создание двух конкурирующих технологий - J2EE и COM+. И та, и другая представляют собой серверы приложений, где реализована большая часть логики, необходимой для обеспечения связки КЛИЕНТ-СУБД. Каждый из этих серверов предоставляет в распоряжение программиста набор правил, которым он должен следовать при реализации логики приложения. Другими словами, современный сервер приложений является хранилищем компонентов, реализованных в соответствии с определенными правилами.

Для чего вообще нужен сервер приложений и почему нельзя обеспечить прямой доступ пользователя к данным? Тому есть, по меньшей мере, три причины.

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

Вторая причина, по которой эта технология сегодня столь популярна, это возможность как изоляции бизнес-логики от приложения-клиента, так и избежания написания сложных хранимых процедур на серверной стороне. Конечно, сегодня различные диалекты SQL, реализованные на серверах баз данных, позволяют делать с данными все или почти все. Практически это достаточно мощные процедурные языки, построенные на основе ANSI SQL92.

Но существуют, как минимум, три недостатка реализации логики с помощью хранимых процедур.

Первый и основной недостаток заключается в том, что необходим программист, который знаком с тем или иным диалектом SQL, для того чтобы держать бизнес-логику вашего приложения под контролем. Кроме всего прочего, SQL-скрипты достаточно сложны для понимания - даже если вы их сами написали всего пару дней назад. Как известно, SQL-код слабо структурирован и очень ограниченно поддерживает повторное использование кода, поэтому проще писать и сопровождать бизнес-логику на более мощном современном объектно-ориентированном языке.

Вторая причина: каким бы мощным ни был диалект SQL, реализованная на нем логика все равно будет работать в десятки, а то и в сотни раз медленнее, чем логика, реализованная на Java, C++ или C#.

Еще одна причина: слабая переносимость нестандартного SQL-кода. Написанием бизнес-логики на северной стороне вы фактически отрезаете себе путь к использованию других баз данных или делаете его очень дорогостоящим. Гораздо проще потом убедить клиента в том, что СУБД, которая используется в вашем приложении, лучше той, которая у него уже есть (хорошо, если у него вообще ничего нет), чем переписывать вашу логику для другого сервера баз данных. Иногда это просто невозможно.

То есть, говоря проще, приложение, построенное по современной архитектуре, должно использовать базу данных в режиме ANSI SELECT/UPDATE и не иметь значительной логики на стороне клиента. Вся логика должна быть реализована в промежуточном слое, называемом сервером приложений.

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

Естественно, если существует жесткая привязка к платформе UNIX, то выбор сервера приложений или платформы для его реализации на сегодняшний день можно считать уже предопределенным - это Java2. В случае принятия решения об использовании готового сервера приложений будет выбран сервер стандарта J2EE - очевидно, что реализация компонентов внутренней бизнес-логики будет выполнена с использованием Java2.

Если вы собираетесь развернуть ваш сервер приложений на платформе Windows, то у вас есть альтернатива в виде C# и COM+. То, что COM+ работает в 2-4 раза быстрее, чем его аналоги, реализованные в соответствии с J2EE-стандартом, подтверждают многочисленные тесты, проделанные как сторонними фирмами, так и самой Microsoft. Объясняется это соотношением нейтив- и интерпретируемого кода: сервера приложений стандарта J2EE сами реализованы с использованием Java2, в то время как С#, напротив, служит только диспетчером, главная задача которого - вызов сравнительно быстродействующего исполнимого нейтив-кода COM+.

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

Иногда программисты и вовсе отказываются от базы данных в пользу создания бизнес-классов и их последующей сериализации на диск. В случае не очень большого объема данных такой подход позволяет сэкономить на стоимости иногда не очень дешевого сервера баз данных. К тому же, такое приложение в некоторых случаях быстрее, чем приложение, использующее сервер баз данных или локальную СУБД в качестве хранилища данных.
Описание тестового приложения и условий тестирования

Для сравнения двух основных платформ для создания серверных приложений автор создал идентичные тестовые приложения на C# и Java. Для компиляции и запуска C# приложения использовалась майкрософтовская реализация DOT.NET машины Rotor версии 1.0. Для компиляции и запуска Java2-приложения использовалась Java-машина и компилятор, входящие в состав JDK 1.3.

Основные характеристики компьютера, на котором происходило тестирование: Pentium II 366, 256 RAM. Операционная система - Windows 2000 SP2 Workstation.

Тестирование проводилось для ста тысяч объектов. Бизнес-класс Man имеет в своем составе три поля: Name, Sex и Age. Два из них имеют тип String, а последнее - тип Integer. Инициализация всех трех полей происходит в конструкторе объекта.

Также определены две функции сравнения объекта - по имени и возрасту.

В первом цикле приложения происходит создание всех бизнес-объектов и их сохранение внутри коллекции ArrayList. Во втором цикле происходят итерации по этой коллекции с вызовом функции сравнения объекта по имени. Когда пятидесятитысячный объект найден, происходит выход из цикла. Третий цикл делает то же, что и второй,- с той лишь разницей, что сравнение проводится по возрасту. В общей сложности происходит сто тысяч итераций по коллекции. Затем - запись всех объектов на диск. ArrayList очищается посредством вызова метода Clear (), после чего происходит чтение всех объектов с диска и сохранение их в ArrayList.

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

Вторая часть теста должна тестировать встроенную сериализацию и десериализацию бизнес-объектов, которая будет происходить при старте вашего сервера, в течение его работы, а также при ее завершении. Конечно, стандартная сериализация - это не самый быстрый и надежный способ сохранения объектов на диск, поскольку при этом интенсивно используются рекурсивные алгоритмы и информация времени выполнения. Использование рекурсивного алгоритма может привести к переполнению стека виртуальной машины. Доступ к информации времени выполнения для определения типа данных тоже является достаточно медленной операцией, связанной с обработкой строк. Но в большинстве случаев, если сериализуемыми являются только бизнес-объекты, а не хранящие их структуры данных (то есть обход коллекции, хранящей бизнес-объекты, происходит посредством циклов), этот механизм дает вполне приемлемые результаты при достаточно простой логике процесса.
Особенности сериализации объектов в C# и Java2

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

Для того чтобы сделать объект записываемым в Java2, необходимо пометить его как объект, реализующий интерфейс implements Serializable. Это указывает компилятору, что необходимо встроить в байт-код объекта байт-код, отвечающий за сохранение объекта этого типа на диск. В C# код сохраняемого объекта должен быть помечен с помощью атрибута [Serializable] перед определением класса - то есть принцип остается тем же, но сам механизм сохранения выглядит немного иначе. Дело в том, что в C# вы сами можете определить свой форматер - класс, который отвечает за формат хранения данных на диске. Так, кроме стандартного бинарного форматера, в C# также предусмотрен форматер, сохраняющий данные в XML-формате, что может быть весьма наглядным, но далеко не быстрым способом представления данных. По умолчанию, в Java2 данные сохраняются в бинарном виде - других форматов хранения данных не предусмотрено.
Результаты тестирования

Для ста тысяч объектов были получены следующие результаты.

Для работы с объектами в памяти мы получили приблизительно 700 мс для C# приложения и 2400 мс - для Java2-приложения. Получается, что DOT.NET-машина при данном количестве объектов работает с объектами в памяти втрое быстрее, чем Java-машина. Возможно, если бы бизнес-класс в C# был описан как структура, мы получили бы еще большую разницу в скорости.

Тестирование скорости при сохранении/чтении данных на диск, напротив, дало не лучшие результаты для C#-приложения. Оно записывало на диск и читало с диска 100000 объектов в течение приблизительно 42-х секунд. Java-приложение справилось с этой же задачей за промежуток времени, равный всего 18-ти секундам,- то есть более чем вдвое быстрей.

Также имеет смысл отметить разницу в размере файлов, созданных приложениями. Для приложения Java2 этот показатель составил 2688961 байт, а для приложения C# - 16188890 байт. Компания Sun Microsystems очень хорошо оптимизировала эту часть своей технологии. Хотя надо отметить, что эти результаты нельзя считать вполне корректными, поскольку в наших объектах было очень много повторяющихся данных. В реальных объектах вашего приложения степень корреляции межу ними будет гораздо ниже - тем не менее, она не исчезнет совсем. Поэтому можно предположить, что весьма значительная разница в скорости все равно останется. Для иллюстрации сказанного ниже приводится диаграмма временных соотношений (см. рисунок).
Выводы

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

Если учесть, что затраты времени на поиск данных в коллекции можно сократить, используя связку "сортировка - бинарный поиск", а также то, что затраты времени при сохранении данных на диск значительно выше затрат времени при осуществлении работы с объектами в памяти,- то для большинства серверных приложений более предпочтительным выбором будет использование платформы Java2.

Однако автор при этом не исключает возможности реализации своих собственных механизмов сохранения данных на диск для приложений, реализованных с использованием C#. В конечном счете, все зависит от бюджета вашего проекта. Если вам нужно построить real-time приложение, где необходима, прежде всего, скорость реакции на сигналы, а устойчивость данных не имеет большого значения, то тут лучшим выбором будет использование C#. Конечно, в этом случае разработка приложения на C++ даст лучшие результаты, если у вас достаточно денег и времени. Еще один плюс в пользу C# - это то, что в месте, где у вас возникают проблемы с быстродействием системы C#, код может быть с легкостью заменен кодом С++. Конечно, это возможно и в Java, однако при этом трудозатраты будут неизмеримо выше.

При тестировании не был учтен такой важный аспект разработки серверного приложения, как скорость передачи объектов через сеть, что объясняется простым отсутствием у автора условий для такого тестирования.

В идеальном случае необходима локальная сеть с полным отсутствием всякой активности в ней. Но, учитывая данные эксперимента с сериализацией данных на диск, можно предположить, что здесь Java2 тоже покажет лучшие результаты.

Недавно Microsoft выпустила новую версию DOT.NET-машины 1.1 - возможно, при тестировании приложения с ее помощью мы бы получили лучшие результаты. Кроме того, сегодня существует JDK 1.4, включающий более оптимальную версию Java2-машины. Вы можете произвести дополнительное тестирование самостоятельно, воспользовавшись кодом приложений, приведенных на диске. Проекты тестовых приложений выполнены с использованием сред разработки JBuilder7 и Visual Studio.NET соответственно.

Java   Теги: .net, Java

Читать IT-новости в Telegram
Информационные технологии
Мы в соцсетях ✉