Как стать автором
Обновить

Мифы и заблуждения насчёт CLR и .NET

.NET *
Последнее время на популярно-технических форумах я часто встречаю ожесточённые споры приверженцев и противников .NET. Эти споры, как правило, начинаются из-за недоразумения, и заканчиваются жестким троллингом, беседами “за жизнь” и сравнением радиусов и удельных плотностей материала различных сферических коней. Обе стороны силятся доказать и аргументировать, но ни одна не хочет посмотреть на предмет спора другими глазами. Хабрахабр не исключение, увы.

Накалу страстей такой беседы позавидовали бы религиозные фанатики. Единственное, что спасает противников от крестовых походов друг на друга, вооружившись вилами и LangSpec’ами — то, что они разделены интернетом.

Так жить нельзя, господа. Мне захотелось исправить эту ситуацию, и выступить с одной из сторон. Этим постом я попробую нанести сообществу непоправимую пользу и разобраться с мифами, на обсуждение которых, а не на взаимное членовредительство, к сожалению, и уходят силы спорщиков. А так как я в своё время перелез с C++ на C# и всё вокруг него, то я буду развенчивать негативные мифы, прибавлять позитива и всячески приукрашивать действительность — а как без этого. И — заметьте — это обойдется совершенно бесплатно для M$. Ну а сделать я это хочу в формате Q&A.


#. C# и CLR — это такая VM, т.е. интерпретатор, а, значит, очень медленно и печально. Мне нужно, чтобы было быстро, очень быстро!

Я не буду рассказывать тут, чем компиляция отличается от интерпретации. Просто хочу заметить вот что: джентльмены, недавний опрос на Хабрахабре показал — большинство разработчиков так или иначе используют “управляемые” языки, которые компилируются не в нативный код, а в байт-коды, исполняемые интерпретаторами — непосредственными или компилирующего типа. Всякие TraceMonkey, LuaJIT, YARV как раз примеры для последней классификации. Это означает, что переход на другую платформу сходной архитектуры заведомо не сделает приложение медленнее. В этом смысле беспокоиться не о чем.

Однако, CLR — это sort of virtual machine, но это не интерпретатор. Еще раз повторюсь: MS.NET это НЕ ИНТЕПРЕТАТОР БАЙТКОДА. Специальный компилятор JIT постепенно преобразует байткод программы в нативный код, примерно такой же, который выдаёт компилятор C++. Текущая реализация CLR — MS.NET и Mono гарантируют, что ЛЮБОЙ код, который будет исполняться, преобразуется в нативный код. При этом для десктопов утверждение еще сильнее: любой код будет откомпилирован только один раз. Причём то, что он компилируется “на лету”, теоретически позволяет более оптимально использовать особенности конкретного процессора, а значит, сильнее соптимизировать код.

Более того, сравнение абсолютных цифр на бенчмарках показывает, что CLR оказывается на порядки эффективнее, чем популярные скриптовые языки типа JavaScript и Ruby, тоже использующие технологию JIT.

#. Языки со сборкой мусора отстают от языков типа C++ по скорости.

Верно, тут вы весьма близки к истине. Но, как и любой холиварщик, немного не договариваете. Правильно фраза будет звучать так: “корректно написанное и целиком вручную оптимизированное нативное приложение без ошибок, использующее специальные методики управления памятью, будет быстрее, чем приложение с автоматической сборкой мусора”.
Но для более-менее серьезного ПО создать такое приложение означает огромное количество затраченных усилий. Значительно превышающее то, которое потребуется для управляемого языка.
Именно поэтому появились языки высокого уровня — в длительной перспективе в среднем код, выдаваемый компилятором, будет содержать меньше ошибок и работать быстрее, чем написанный вручную.

И — да — тупые цифры не лгут: выделение памяти в языках со сборкой мусора выполняется БЫСТРЕЕ, и _не_ фрагментирует кучу, в отличие от с++. Обработка исключений в управляемых языках тоже выполняется быстрее.

А тут еще в дело вступает фактор времени, и стоимости разработки, включая количество ошибок. Потому что ошибка повреждения или утекшей памяти… хм… когда же я её видел в CLR последний раз? Лет 10 назад, не меньше.

#. Программы на CLR жрут очень много памяти. Прям вааще всё жрут, ничего не оставляют…

Хм. Сравнимое нагруженное Ruby-on-Rails-приложение на сервере кушает 100-150МБ RAM, примерно столько же, сколько и ASP.NET CLR сайт. Тут нет большой разницы.
Конечно, в небольших скриптовых задачах тот же Ruby оказывается гораздо эффективнее. Но вопрос не о скриптовых задачах — на проектах из реальной жизни, которые приносят деньги, аппетиты CLR выглядят соразмерными другим технологиям, и я не могу согласиться с определением “жрут очень много”.

#. Ну ладно, ладно, GC это хорошо. Но сборщик мусора — очень капризное животное, там есть огромное количество настроек. Их же никто не может корректно выставить — ручное вмешательство только вредит. GC в моём ZZZ работает и так! Сам!

Между прочим, CLR обладает одним из лучших сборщиков мусора на сегодняшний день. Первый его вариант был написан на LISPe, чтобы явственнее выразить семантику отношений между объектами в памяти и выполнить автоматический анализ корректности алгоритма, а затем переписан на С++. С тех пор прошло много времени, GC был обкатан миллионами разработчиков и не меньшим количеством проектов. Не течёт, что ни делай!

В качестве настроек выступает один ключ в файле конфигурации gcServer=”true/false”. Включает параллельную сборку мусора, а так же другие оптимизации. По умолчанию стоит в false, чтобы не мешать интерактивному режиму UI (работа gc незаметна для UI) на однопроцессорных машинах. В CLR 4.0 появились новые настройки, но суть та же — отлично работает “из коробки”, убирайте свои пассатижи подальше.

#. А в моём любимом языке ZZZ есть FFI, и поэтому я могу писать к нему расширения на С, если мне нужна скорость. Ни разу, правда, не писал, ну и что! Ведь могу же! А что в CLR/C#, надо всё переписывать на управляемый язык?

Очень рад за ZZZ. Вы удивитесь, но в CLR тоже присутствует возможность вызывать функции из нативных dll, написанных на старом добром С. И, конечно, передавать туда данные и получать обратно. Причем, в отличие от большинства FFI, вам не нужно проектировать dll под FFI — использовать соглашения по вызову и специальные типы данных. CLR всеяден, его можно гибко настроить на поедание почти любой библиотеки. Отдельным образом включена и автоматизирована поддержка COM, для более удобного доступа к возможностям Windows.
Это называется Interop/Platform Invoke

#. Окэ, я могу много чего написать на С. Но не буду же я писать сам всё! В .NET отсутствуют нужные бибилиотеки; а чтобы работать с БД, нужно покупать MSSQL за сто тыщ миллионов денег!

Вам и не нужно писать всё. В .NET присутствует отличная stdlib, называемая BCL (Base Class Library). Там есть многое из того, что вам понадобится: файлы, сокеты/сеть, http и web, регулярные выражения, SQL и работа с данными, xml и веб-сервисы и т.д.
Если вам нужно что-то, чего нет в BCL, скорее всего, такая библиотека уже есть. Либо можно воспользоваться нативной — так сделаны обертки к OpenGL и OpenAL, bass.dll (звук) и много чего.

Для .NET написаны провайдеры для MySQL и Oracle, SQLite и PostgresQL, они стабильны и отлично работают. Да что там SQL, есть и MongoDB и свои объектные БД, есть клиент к Memcache и RabbitMQ. Есть свои ServiceBus и MessageQueue, а API к существующим системам писать очень просто.

#. Писать для CLR можно только из Visual Studio. И только под Windows. И то, и то опять стоит денег.

Неправда. Есть SharpDevelop, который достаточно хорош для бесплатной среды; есть MonoDevelop, который тоже хорош, и работает как по Win, так и в *nix. Есть плагины к Eclipse; кстати, при помощи IKVM.NET для запуска Eclipse не нужна Java, хватает одного CLR.

Облегченная версия Visual Studio Express позволяет создавать полноценные приложения в Win. Бесплатного MS SQL Express хватит надолго для большинства проектов.

Есть инструменты для отладки, профилирования, налаживания процесса Continuous Integration, сами написанные на .NET. Есть свои инструменты типа make/ant — NAnt, msbuild.

Качай@Устанавливай!

#. Место CLR — на сервере. А Mono — страшная неюзабельная ненадежная гадость, не выросшая из пеленок MiguelDeIcaza’s Labs ©.

Точно. На сервере приложений и на веб-сервере — в CLR есть свои Rails (ASP.NET MVC), есть свой Hibernate и десятки других ORM. Подойдёт для всего. Ну это разве страшно — мы все постепенно переползаем в веб.

С другой стороны, создатели Unity3D с вами не согласны. Это такой плеер, который хостит CLR-среду прямо в вашем браузере, а программы-сценарии для него пишутся на .NET языках. Очень быстрый, красивый. 3D уже сейчас. Не надо ждать Flash Player с поддержкой GPU.

Кстати, а вы слышали, что приложения Mono компилируется и для iPhone и iPad (#MonoTouch)? Да и тот же Unity3D это умеет.

#. Использование CLR заставляет меня переходить на C#, я не хочу его учить!

И совершенно не нужно. Да, в C# наиболее полно доступны все возможности CLR, но никто не заставляет пользоваться именно им. CLR — это не только C#, это отличная платформа и BCL, предоставляющая качественную объектную модель и инструменты. Существует огромное количество языков — новых, таких, как Boo, Nemerle, F#, или ранее известных: Delphi, Ada, Lisp, VB, php, в качестве back-end использующих CLR.
С этой точки зрения CLR похожа на LLVM — предоставляет сервисы нижнего уровня, такие, как IL (байт-код) и JIT, сборка мусора, объектная модель, общая система типов, стандартная библиотека, система безопасности и т.д.

#. С# это быдлоязык для ыnterprise, он застрял в прошлом веке, а в моём языке ZZZ каждые полгода новые фишечки!

Да, C# сейчас плотно обосновался в low-cost секторе enterprise — всё благодаря его характеристикам: на нем достаточно просто писать, статическая типизация и управляемая среда позволяет исключить целый класс ошибок, присущих скриптовым языками или языкам более низкого уровня, IDE предоставляет доступ ко всем нужным инструментам в пару кликов, встроенная прямо в IDE документация и первоклассный IntelliSense.

Благодаря этому решения на C#/CLR обходятся не так дорого, как в Java.

В C# соблюдается принцип обратной совместимости, но это не мешает добавлять новые features в язык. Уже сейчас есть параметрический полиморфизм (это когда Vector), лямбда-функции и замыкания, впервые из всех языков появились LINQ (Language-integrated queries) на базе ограниченного цитирования, присутствует вывод типов, появился целый пласт DLR. В 5.0 версии появляется встроенная поддержка асинхронного программирования.

CLR/С# не так плох, как вы думаете, и это ничего не стоит проверить. Но если вам мало C#, есть F# (порт Caml) и Nemerle (гибрид C# и функционального языка), есть даже CLR C++ — берите из двух миров то, что вам надо, и совмещайте.

#. Так, алоэ, я кое-что вспомнил. О какой кросcплатформенности речь, когда чтобы запустить под Mono, мне надо всё перекомпилировать. Это же как в старом добром С, чем лучше-то?!

Очередная глупость. Я не знаю, кто вам сказал, но в целом полностью управляемое CLR-приложение, скомпилированное под Windows, НЕ НУЖНО ПЕРЕКОМПИЛИРОВАТЬ. Можно ПРОСТО перенести на Linux с установленным Mono, скомандовать mono myapp.exe, и оно запустится. И наоборот тоже работает. Я проверял.

Правда, здесь вступает в ход связывание с библиотеками. Это как gems в Ruby — если этот конкретный gem использует нативные библиотеки, то вам нужно установить эти самые нативные библиотеки. Но а вообще — полно чисто Ruby-гемов.
No magic, как-то так.

#. Приложения .NET используют реестр. Опять эта головная боль с управлением версиями ПО, установкой и удалением программ?

Нет. Все управляемые приложения .NET можно распространять по модели deploy-by-copy — скопируй в нужную папку и запускай оттуда. Они не лезут в реестр, не заглядывают в системные папки.

Если же вы хотите использовать общую управляемую библиотеку, то специальный механизм, называемый GAC (Global Assembly Cache), используя механизмы криптографии, позаботится об отсутствии дублирования, о том, что нужная вам библиотека — именно та и именно той версии, которую вы ждёте.

#. А вот мои знакомые программисты… Они говорили, что в комплект разработчика на Visual Studio IDE и C# входит обязательный ректальный виброзонд и инструкция по его непрерывному ношению!

OMFG O_o! Я абсолютно ответственно заявляю: ваших знакомых программистов обманули. Я бы порекомендовал вам пойти и помочь им отказаться от ношения самозваного зонда, но, боюсь, что они уже вошли во вкус и не смогут… Но ведь MS и CLR тут не при чём, так?

Выводы

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

В общем и целом, я рассказал, как обстоит дело, чем, надеюсь, причинил немало добра своим коллегам по цеху CLR. Надеюсь, теперь не будет дурацких вопросов, типа “зачем C#, если есть Python, а при нём GC”.

Идти в эту сторону по жизни или нет — выбор за вами. Ничего не мешает совмещать. Я пишу на .NET за еду и на Ruby для души.
Теги:
Хабы:
Всего голосов 226: ↑170 и ↓56 +114
Просмотры 34K
Комментарии Комментарии 240