Будущее WinRT или Going Native 2.0Источник: habrahabr OpenMinded
Alexandre Mutel - создатель самой быстрой и самой полной .NET обертки для DirectX, единственной, поддерживающей Windows 8 Metro, работает R&D разработчиком игрового движка в SiliconStudio, участник французской демо-группы FRequency. В последнее время мы слышим много шума о возвращении идеи "Going Native" после эры управляемых языков, таких как Java и .NET. В прошлом году, когда WinRT был только представлен, начали появляться недалекие комментарии, которые утверждали, что что .NET умер, а С++ возвращается во всей своей красе - истинный и единственно верный способ для разработки приложений, в то время, как JIT начинает все чаще появляться в мире скриптовых языков (JavaScript активнее всех использует преимущества JIT). Любой код так или иначе станет нативным перед выполнением - разница лишь в длине пути, по которому он пройдет, чтобы стать нативным, и насколько оптимизированным он будет. Значение слова "native" немного изменилось и стало неразрывно связано со словом "производительность". Даже будучи сильным пропагандистом управляемого языка [C#], его производительность на самом деле ниже хорошо написанного С++ приложения. Получается, мы должны просто принять этот факт и вернуться к C++, когда такие штуки как WinRT будут для нас основой межязыкового взаимодействия? По правде говоря, я бы хотел, чтобы .NET умер, и этот пост о том, почему и зачем. Эра управляемых языковДавайте пересмотрим недавнюю историю разработки на управляемых языках и отметим текущие проблемы. Помните слоган Java? "Write once runs everywhere". Это было представление новой парадигмы, когда полностью "безопасный" язык, основанный на виртуальной машине, связанный с богатым набором API, предоставит возможность с легкостью разрабатывать приложения под любую ОС и платформу. Это было начало эры управляемых языков. В то время как Java была достаточно успешно принята в разных отраслях разработки, она также была отвергнута многоми разработчиками, которые были в курсе особенностей управления памяти, недостаточно оптимизированного JIT (хотя с тех пор все значительно улучшилось), огромного количества плохих архитектурных решений, вроде отсутствия поддержки структур, прямого доступа к памяти, а вызовы нативного кода через JNI были чрезвычайно неэффективными и трудоемкими (и даже недавно они рассматривали возможность убрать все нативные типы объектов и сделть все object - что за ужасная идея!). Также Java не смогла выполнить обещане, данное в самом слогане - на самом деле невозможно охватить единым API все возможности каждой платформы, что привело к таким вещам, как Swing - мягко говоря не самый оптимальный UI фреймворк. Также, изначально Java была разработана в расчете на единственный язык программирования, хотя многие увидели в JIT и байткоде возможность портировать скриптовые языки на Java JVM. В начале эры управляемых языков Microsoft пыталась войти на рынок Java с собственными расширениями для языка (об окончании этой истории знают все) и в итоге обзавелась собственной платформой для управляемых языков, которая в некоторых аспектах была лучше спроектирована и скомпонована: начиная с байткода, ключевого слова unsafe, вызова нативного кода, легковесного но очень эффективного JIT и NGEN, быстро развивающегося языка C#, C++/CLI и т. д. Изначально учитывая межязыковое взаимодействие и без бремени слогана Java (хотя Silverlight на MacOS или Moonlight были неплохими попытками). Обе платформы использовали похожий монолитный стек: метаданные, байткод, JIT и сборщик мусора - все это тесно связано. Соответственно, с производительностью были похожие проблемы: JIT подразумевает задержку при запуске, а выполнение кода не такое быстрое, как должно бы быть. Основные причины:
Но даже с такой недостаточной производительностью, управляемая экосистема с универсальным фреймворком - это король продуктивности и межязыкового взаимодействия, с достойной общей производительностью для всех поддерживаемых языков. Апогеем эры управляемых языков был вероятно запуск WindowsPhone и VisualStudio 2010 (которая использовала WPF для рендеринга интерфейса, хотя сам WPF работал поверх приличного количества нативного кода). Управляемые языки были единственным дозволенным способом разрабатывать приложения в то время. Это было не лучшее, что могло случиться, принимая во внимание длинный список неразрешенных проблем с производительностью .NET, достаточно длинный, чтобы стимулировать "нативных разработчиков" нанести ответный удар, и они имели на это полное право. Так вышло, что это означает в каком-то смысле отказ от .NET. Я не так много знаю о внутренней кухне Microsoft, но судя по частым сообщениям, там наблюдается сильное противостояние между подразделениями. Хорошо это или плохо, но для .NET в последние годы создается впечатление, что у Microsoft заканчивается запал (например, нет практически никаких значительных улучшений в JIT/NGEN, множество неразрешенных запросов на улучшение производительности, включая такие вещи, как SIMD, которых разработчики ждут уже очень долго). И мне кажется, что все эти изменения возможны только в том случае, если .NET будет глобальной стратегией и при сильной поддержке и участии всех подразделений. В то же время, Google начал продвигать свою технологию NativeClient, позволяющую запускать нативный код в песочнице прямо из браузера. В прошлом году, следуя тренду "Going Native", Microsoft объявила, что даже HTML5, разработанный для следующего IE, будет нативным! Sic. В "Reader Q&A: When will better JITs save managed code?" Herb Sutter, один из евангелистов "Going Native", приводит некоторые интересные доводы о том, что философия "Going Native" думает о JIT ("Can JITs be faster?" ответный пост Miguel de Icaza) с множеством неточных фактов, но давайте просто рассмотрим ключевой: даже если JIT в будущем станет лучше, управляемые языки уже сделали выбор между производительностью и безопасностью в пользу безопасности. Тем самым для них уже заказан путь в высшую лигу. И в этот момент появляется WinRT, который немного сглаживает острые углы. Используя часть философии .NET (метаданные и некоторые общие типы, такие как строки и массивы) и старую добрую модель COM (как общий знаменатиль для нативного межязыкового взаимодействия), WinRT пытается решить проблемы взаимодействия языков за пределами мира CLR (что означает отсутствие потерь производительности у C++) и предоставить более современное API для ОС. Является ли это ответом на главный вопрос жизни, вселенной и всего такого? Не особо. Для WinRT выбрали курс на явное сближение технологий, который потенциально может привести к великолепным вещам, но пока что нет уверенности в правильном выборе пути. Но что может быть этим "правильным путем"?
Going Native 2.0 - производительность для всехПроверки на безопасность могут иметь негативное влияние на производительность, но управляемый код не обречен всю жизнь запускаться только поверх медленного JIT (например, Mono умеет запускать C# код, нативно скомпилированный через LLVM на iOS/Linux) и было бы довольно легко расширить байткод небезопасными инструкциями чтобы предоставить контролируемое улучшение производительности (вроде отмены проверки границ массива). Но самой явной проблемой сейчас является отсутствие сильной инфрастуктуры для межязыковых компиляторов. Начиная с компилятора, используемого в IE 10 JavaScript JIT, .NET JIT и NGЕN компиляторы, Visual C++ компилятор (и многие другие) - все они используют разный код для практически одной и той же трудоемкой и сложной задачи - генерации эффективного машинного кода. Имея в распоряжении единый компилятор - это очень важный шаг для предоставления высокопроизводительного кода, доступного для всех языков. Felix9 на Channel9 обнаружил, что Microsoft в действительности может работать над этой проблемой. Это определенно хорошие новости, но проблема "производительности для всех" лишь небольшая часть от общей картины. На самом деле "верный путь", упоминаемый ранее, - это более широкая интегрированная архитектура, не только улучшенный LLVM стек, но поддержанная многолетним опытом Microsoft в разных областях (компилятор C++, JIT, сборщик мусора, метаданные и т. д.) система, которая будет предоставлять полностью расширяемую и модульную "CLR", состоящую из:
Идея очень близка к стеку CLR, однако она не принуждает приложения запускаться поверх JIT компилятора (да, в .NET есть NGEN, но он был разработан для ускорения загрузки, не для ускорения общей работы, кроме того это черный ящик и он работает только со сборками, установленными в GAC) и позволяет смешанные стратегии выделения памяти: с использованием сборщика мусора и без него. В подобной системе межязыковое взаимодействие будет более простым, не жертвуя производительностью ради простоты и наоборот. В идеале, сама ОС должна быть построена на базе подобной архитектуры. Возможно именно эта идея была (есть?) в основе таких проектов, как Redhawk (это что касается компилятора) или Midori (что касается ОС). В подобной интегрированной системе, возможно, только драйверы будут требовать прямого доступа к железу. Felix9 также раскопал, что промежуточный байткод, более низкоуровневый, чем MSIL (байткод .NET), называемый MDIL, уже может использоваться и он может быть именно тем промежуточным байткодом, описываемым ранее. Хотя, если посмотреть на соответствующий патент "INTERMEDIATE LANGUAGE SUPPORT FOR CHANGE RESILIENCE", то в спецификации можно найти x86 инструкции, которые не совсем подпадают под определение архитектурно независимого байткода. Возможно они оставят MSIL без изменений и задействуют MDIL на более низком уровне. Скоро узнаем. Итак, какие проблемы с этой точки зрения решает WinRT? Метаданные, немного API, поддерживающего песочницы и межязыковое взаимодействие в зачаточной стадии (хотя есть общие типы данных и метаданные). Как видим, не густо, эдакий COM++. Также очевидно, что WinRT не предоставляет продвинутые оптимизации, когда мы используем его API. Например, нам не позволено иметь структуру со встраиваемыми методами. Каждый вызов метода в WinRT - это виртуальный вызов, который обязательной пойдет через таблицу виртуальных методов (а в некоторых случаях требуется несколько виртуальных вызовов, когда например используется статический метод). Простейшие чтение-запись свойства потребуют виртуального вызова. Это явно неэффективно. Судя по всему WinRT нацелен только на более высокоуровневые API, не позволяя сценарии, в которых мы бы хотели использовать высокопроизводительный код везде, где это возможно, минуя слой виртуальных вызовов и невстраиваемого кода. В итоге мы имеем расширенную модель COM - это не совсем то, что можно было бы назвать "Building the Future".
Продуктивность и производительность для C# 5.0Язык вроде C# был бы идеальным кандидатом для такой модульной CLR системы, и мог бы с легкостью переноситься на уже существующий промежуточный байткод. Но чтобы эффективно использовать подобную систему, C# должен быть улучшен в нескольких аспектах:
Кроме производительности есть и другие не менее важные области:
Основная идея в том, что нужно меньше добавить в C#, чем убрать из C++, чтобы полностью задействовать возможности подобной интегрированной системы, увеличить продуктивность разработчика и без сопутствующих потерь производительности. Кто-то может поспорить, что С++ уже предлагает все это и даже более, но именно поэтому С++ такой загромажденный (с точки зрения синтаксиса) и опасный для большинства разработчиков. Он позволяет небезопасный код абсолютно везде, в то время как в каждом приложении есть вполне определенные места, где он действительно нужен (что приводит к проблемам с памятью, которые проще исправить, если бы эти места были явно обозначены в коде, как это сделано с ключевым словом asm). Намного проще и безопаснее отслеживать подобные области в коде, чем иметь их повсеместно.
Что же далее?Мы надеемся, что Microsoft выбрала путь от общего к частному и начала с выпуска WinRT, предоставляющего универсальное API для всех языков и простое межязыковое взаимодействие. И что затем они представят все эти более продвинутые возможности в следующих версиях их ОС. Но это идеальная ситуация и будет интересно наблюдать, сможет ли Microsoft справиться с этим. Даже если недавно объявили, что .NET приложения в WP8 будут иметь преимущества компиляции в облаке, до сих пор мы мало что знаем об этом: это просто адаптированный NGEN (который, напомню, не ориентирован на производительность и генерирует код очень похожий на тот, что генерирует JIT) или еще не представленный компилятор RedHawk? У Microsoft наверняка что-то есть в загашнике, учитывая многие годы разработки компиляторов C++, JIT, сборщика мусора и всех связанных R&D проектов, которые у них есть… Подводя итоги - .NET должен умереть и уступить свое место более интегрированной, ориентированной на производительность, общей среде, где бы управляемое (безопасность и продуктивность) и неуправляемое (производительность) были бы тесно связаны. И это должно быть структурной частью следующего витка развития WinRT. |