Пользователь
0,0
рейтинг
20 августа 2012 в 10:30

Будущее WinRT или Going Native 2.0 перевод

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 подразумевает задержку при запуске, а выполнение кода не такое быстрое, как должно бы быть. Основные причины:

  • JIT производит недостаточные оптимизации в сравнении с C++ -O2, потому что он должен генерировать код очень быстро (также, в отличае от Java HotSpot JVM, .NET JIT не может на лету подменять существующий код на более оптимизированный).
  • Типы .NET, такие как Array, всегда делают проверку границ при доступе (не считая простых циклов, где JIT может убирать проверки, если условие завершения цикла меньше или равно длине массива).
  • Сборщик мусора останавливает все потоки во время сборки (хотя новый сборщик мусора в .NET 4.5 в этом отношении несколько улучшили), что может приводить к непредсказуемым падениям производительности.

Но даже с такой недостаточной производительностью, управляемая экосистема с универсальным фреймворком — это король продуктивности и межязыкового взаимодействия, с достойной общей производительностью для всех поддерживаемых языков. Апогеем эры управляемых языков был вероятно запуск 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», состоящую из:

  • Промежуточный язык среднего уровня. Поддерживающий отражение, очень похожий на LLVM IR или байткод .NET, определяющий общие типы данных (примитивы, строки, массивы и т. д.). Должен быть доступен API похожий на System.Reflection.Emit. Векторизованные типы (SIMD) должны быть такими же базовыми, как int и double. IL код не должен ограничиваться только CPU, но также должен позволять делать вычисления на GPU (как это делают AMP расширения для C++). Должна быть возможность представить байткод HLSL с помощью этого IL, используя преимущества единой инфрастуктуры компиляторов (см. далее). IL без типов также должен быть доступен, чтобы было проще переносить на него динамические языки программирования.
  • Динамически связываемые библиотеки и исполняемые файлы, такие как сборки .NET, предоставляющие метаданные, IL код, поддерживающие отражение. Во время разработки код должен связываться со сборками (IL кодом), а не с устаревшими заголовочными файлами C/C++).
  • Компилятор из IL в машинный код, который может быть интегрирован в JIT, настольное приложение или в облачный компилятор, или комбинация всего этого. Этот компилятор должен предоставлять векторизацию настолько, насколько это поддерживает целевая платформа. IL код должен компилироваться в машинный код во время установки или развертывания, используя информацию об архитектуре системы (во время разработки это можно сделать сразу после компиляции в IL). Этапы компиляции должны быть доступны через API и должны предоставлять точки расширения везде, где это возможно (предоставляя доступ к IL, оптимизации IL, или встраиванию собственных трансформаций из IL в машинный код). Настройки оптимизации должны варьироваться от быстрой компиляции (вроде JIT) до агрессивной оптимизации (заранее скомпилированные приложения или горячая замена кода в JIT на более производительный). Профиль приложения может также использоваться для автоматической подстройки локализованных оптимизаций. Этот компилятор должен поддерживать продвинутые cценарии использования JIT, такие как динамический анализ кода, On Stack Replacement (OSR, позволяющий замену кода для сложных вычислений на более оптимальный код прямо во время выполнения), в отличае от текущего компилятора .NET JIT, который компилирует метод во время его первого запуска. Оптимизации подобного рода очень важны в динамических сценариях, когда вывод типов (type inference) происходит уже после компиляции (как в случае Javascript).
  • Расширяемый компонент для выделения памяти, позволяющий параллельные выделения памяти. Сборщик мусора будет одной из возможных реализаций. Большая часть приложений будут использовать именно его для большинства объектов, в то время как наиболее критичные для производительности объекты будут использовать другие стратегии выделения памяти (вроде подсчета ссылок, используемого в COM/WinRT). Не дожно быть никаких ограничений на использование нескольких стратегий выделения памяти в одном приложении (имено это и просходит в .NET, когда приложению приходится прибегать к использованию вызовов нативных функций для создания объектов за пределами 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# должен быть улучшен в нескольких аспектах:

  • Больше небезопасных конструкций, когда мы могли бы выключить «управляемое» поведение вроде проверки границ массивов (вроде «супер небезопасного режима», когда мы могли бы использовать инструкции кеширования в CPU для доступа к элементам массива, подобного рода «продвинутые» штуки сейчас невозможно делать с управляемыми массивами без использования недокументированных трюков).
  • Конфигурируемый оператор new, который бы поддерживал разные схемы распределения памяти.
  • Векторизованные типы (вроде float4 в HLSL) должны быть добавлены к базовым типам. Об этом уже давно просили (с ужасными патчами в XNA WP для «решения» этой проблемы).
  • Легковесное взаимодействие с нативным кодом: в текущем состоянии переход от управляемого к неуправляемуму коду довольно затратный даже без передачи каких бы то ни было параметров. Переход к неуправляемому коду должен быть возможен без x86/x64 инструкций пролога/эпилога, которые сейчас генерируются в .NET JIT.


Кроме производительности есть и другие не менее важные области:

  • Обобщения (generics) везде — в конструкторах и неявных преобразованиях типов, с более продвинутыми конструкциями (контрактами для операторов и т. д.), ближе к гибкости шаблонов С++, но более безопасные и менее загроможденные.
  • Наследование и финализаторы в структурах (чтобы позволить выполнение легковесного кода при завершении метода без использования громоздких паттернов вроде try/finally и using).
  • Больше метапрограммирования. Методы расширения для статических типов, примеси (добавление содержимого класса внутрь другого класса, удобно для вещей вроде математических функций), модификация классов/типов/методов во время компиляции (например, методы, которые бы вызывались во время компиляции для добавления других методов или свойств к классу, чем-то похоже на eigenclass в Ruby, вместо использования T4 шаблонов для генерации кода).
  • Встроенный литерал или тип, которым бы можно было выразить ссылку на объект языка (класс, свойство, метод), используя простую конструкцию вроде: symbol LinkToMyMethod = @ MyClass.MyMethod; вместо использования Linq выражений. Это сделало бы более надежным код для таких вещей как INotifyPropertyChanged или упростило бы все системы, основанные на свойствах, вроде WPF (который в текущем состоянии содержит много дублирующего кода).


Основная идея в том, что нужно меньше добавить в C#, чем убрать из C++, чтобы полностью задействовать возможности подобной интегрированной системы, увеличить продуктивность разработчика и без сопутствующих потерь производительности. Кто-то может поспорить, что С++ уже предлагает все это и даже более, но именно поэтому С++ такой загроможденный (с точки зрения синтаксиса) и опасный для большинства разработчиков. Он позволяет небезопасный код абсолютно везде, в то время как в каждом приложении есть вполне определенные места, где он действительно нужен (что приводит к проблемам с памятью, которые проще исправить, если бы эти места были явно обозначены в коде, как это сделано с ключевым словом asm). Намного проще и безопаснее отслеживать подобные области в коде, чем иметь их повсеместно.

Что же далее?


Мы надеемся, что Microsoft выбрала путь от общего к частному и начала с выпуска WinRT, предоставляющего универсальное API для всех языков и простое межязыковое взаимодействие. И что затем они представят все эти более продвинутые возможности в следующих версиях их ОС. Но это идеальная ситуация и будет интересно наблюдать, сможет ли Microsoft справиться с этим. Даже если недавно объявили, что .NET приложения в WP8 будут иметь преимущества компиляции в облаке, до сих пор мы мало что знаем об этом: это просто адаптированный NGEN (который, напомню, не ориентирован на производительность и генерирует код очень похожий на тот, что генерирует JIT) или еще не представленный компилятор RedHawk?

У Microsoft наверняка что-то есть в загашнике, учитывая многие годы разработки компиляторов C++, JIT, сборщика мусора и всех связанных R&D проектов, которые у них есть…

Подводя итоги — .NET должен умереть и уступить свое место более интегрированной, ориентированной на производительность, общей среде, где бы управляемое (безопасность и продуктивность) и неуправляемое (производительность) были бы тесно связаны. И это должно быть структурной частью следующего витка развития WinRT.
Перевод: Alexandre Mutel
Алексей Сигов @OpenMinded
карма
133,5
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое

Комментарии (45)

  • +12
    Кажется MS явно дали понять что C# и XAML для обычных приложений, а C++ и DirectX для хардкора. Для пущего хардкора писать библиотеки на C++ а потом использовать их в C#.
    • +1
      А если хочется C# и DirectX? Без сторонних библиотек вроде SharpDX это невозможно. XNA безусловно хорош, но он устарел и скорее мертв, чем жив.
  • +8
    Основная идея в том, что нужно меньше добавить в C#, чем убрать из C++, чтобы полностью задействовать возможности подобной интегрированной системы, увеличить продуктивность разработчика и без сопутствующих потерь производительности.

    Мне кажется, что при добавлении всех перечисленных фич (если их вообще можно добавить с учетом обратной совместимости и минимального сохранения идеологии C# и .Net) C# станет не менее запутанным чем С++.
  • +8
    Вроде C# был сделан для бизнес-приложений, а не для сложных и медленных расчётов. А в них нет разницы, открылось окошко за 0,1 с или за 0,2 с.
    • +1
      С таким подходом, когда всем плевать на производительность (и иногда дизайн) бизнес приложений, не удивляйтесь, что в мире существуют миллионы человек, ненавидящих свою работу.
      • +8
        Не утрируйте. В любом программном продукте на производительность плевать в определённых пределах. Если для игр этот предел в районе 0,1 секунды, то для бизнес-приложений достаточно и 0,5 с. Если у ПО (любого) отзывчивость не удовлетворяет данным требованиям, то тогда нужно оптимизировать.
        • +2
          Верно, верно. Причем, речь же не идет о разнице в 1-2 секунды. Когда там десятые доли — ничего страшного.

          P.S. Единственное, где даже такие задержки недопустимы — аэрокосмические технологии. Но там и подход вообще в корне другой.
          • 0
            А какой там подход?
            • 0
              Там самый что ни на есть real-time нужен. Там нет временных решений, нет компромиссов, и уж тем более никто не жертвует производительностью в пользу удобства разработки. Нет задачи универсальности/мультиплатформенности. И все должно работать просто идеально.

              На Хабре проскакивало несколько интересных статей на эту тему — всецело советую для ознакомления.
              • НЛО прилетело и опубликовало эту надпись здесь
      • 0
        открытие окна за 0,2с != плевать на производительность
  • +15
    JIT производит недостаточные оптимизации в сравнении с C++ -O2, потому что он должен генерировать код очень быстро (также, в отличае от Java HotSpot JVM, .NET JIT не может на лету подменять существующий код на более оптимизированный).

    до генерации нативного кода, компилятор уже производит многие оптимизации MSIL.

    Типы .NET, такие как Array, всегда делают проверку границ при доступе (не считая простых циклов, где JIT может убирать проверки, если условие завершения цикла меньше или равно длине массива).


    VS->Project Settings->Build->Optimize code.
    VS->Project Settings->Build->Configuration->Release

    в mono это также отключаемо.

    Сборщик мусора останавливает все потоки во время сборки (хотя новый сборщик мусора в .NET 4.5 в этом отношении несколько улучшили), что может приводить к непредсказуемым падениям производительности.

    смотрим, мою недавнюю статью на тему GC.

    облачный компилятор


    compiler as service — это еще понятно, но ОБЛАЧНЫЙ???

    Легковесное взаимодействие с нативным кодом:

    как быть с недетерминированным управлением памяти с GC и C++? проблема еще не решена.
    может быть CXXI, но там также есть ограничения.

    Также очевидно, что WinRT не предоставляет продвинутые оптимизации, когда мы используем его API.


    как может API (!!!) оптимизировать код, его использующий???

    Векторизованные типы (вроде float4 в HLSL)


    уже есть! MS Research Accelerator v2
    • 0
      Типы .NET, такие как Array, всегда делают проверку границ при доступе (не считая простых циклов, где JIT может убирать проверки, если условие завершения цикла меньше или равно длине массива).

      VS->Project Settings->Build->Optimize code.
      VS->Project Settings->Build->Configuration->Release

      в mono это также отключаемо.

      Не уверен. Есть статья на эту тему.
      Хорошо бы чтобы при unsafe { } не делалась проверка границ.
      • 0
        здесь существует небольшая грань — либо проверка границ явная (и оптимизация возможна), либо ситуация типа:
        for (int i = a.Length - 1; i >= 0; i--)
        

        где как программисту цикл понятен, но не компилятору (ибо компилятор обрабатывает только обобщенные ситуации).

        так следует использовать IEnumerable с включенной оптимизацией (т.к. границы не проверяются).

        если по mono, то презентация mono for game developers (слайд #39).

        и да, O2 — не панацея, т.к. можно приводить к гейзенбагам.
      • 0
        и, кстати, при unsafe не делается проверка границ (!!!).
        • 0
          Ой, я ошибся. Я имел ввиду чтобы делалась :)
  • 0
    В загашнике у MS компиляция C# сразу в нативный код.
  • +8
    Для меня .NET — это прежде всего клей, позволяющий совместно использовать разные библиотеки и языки без написания бесконечных переходников и обёрток. Какая платформа способна предложить мне такой клей? Я такой платформы не знаю.

    Производительность .NET меня полностью устраивает.
    • 0
      я вас здесь поддерживаю и клей — прекрасная метафора)
      Но я не пишу высокопроизводительных вещей, вы, наверное, тоже)))
    • 0
      Это клей в своей песочнице, склеивающий только *# языки + один внешний C++

      Хотя нельзя не согласиться, что библиотек красивых к нему приклеили немало…
    • 0
      У IBM в 90х была нехиленькая такая платформа, но они самоустранились
  • +1
    >«Подводя итоги — .NET должен умереть...»

    Карфаген должен быть разрушен!
    • 0
      Что то много в последнее время всяких авторитетных людей, пророчащих смерть/разорение/полосу неудач другим людям и их творениям…
      • +1
        Не знаю, где вы усмотрели разорение и полосу неудач. Я вижу только желание более активного развития и улучшения.
        • –1
          В фразе ".net должен умереть" © Кэп
  • +4
    Автору спасибо за перевод, кстати. А то сейчас частенько ужасные переводы начали мелькать в ленте (и даже на главной)
  • +5
    Каждый вызов метода в WinRT — это виртуальный вызов, который обязательной пойдет через таблицу виртуальных методов (а в некоторых случаях требуется несколько виртуальных вызовов, когда например используется статический метод). Простейшие чтение-запись свойства потребуют виртуального вызова. Это явно неэффективно.


    Заявление автора про «явную неэффективность» — подтасовка фактов. Виртуальные функции, конечно, будут вызываться медленнее невиртуальных. В абсолютных числах. Но если посмотреть накладные расходы в тактах на вызов функции и на то, что эта функция делает (а функции ведь что-то делают?), то непосредственно вызов будет ничтожно малой величиной. Профайлинг усредненного приложения (а я их много профайлил) показывает накладные расходы на выовы функций 1-2%. Это не та неэффективность, о которой имеет смысл говорить :).
    • +3
      Хочу добавить по поводу оптимизации вызовов виртуальных методов. В 1993 году вышел язык программирования Self, виртуальная машина которого поддерживала JIT компиляцию (первый в мире JIT компилятор). Self — это динамически типизированный язык, основаный на прототипах. Язык очень динамический. Например, там даже доступ к полям объекта происходит только через посылку сообщений, плюс штатная возможность менять иерархию наследования объекта, плюс множественное наследование. В общем, в Self есть куча особенностей затрудняющих создание эффективной реализации VM.

      В результате работ над Self-90 и Self-93 оказалось, что у того около 25% всех точек вызовов являются не мономорфными, а полиморфными. То есть, местами где значительное число сообщений посылаются объектам разных классов. Для ускорения работы таких случаев используется polimorphic inline cache (PIC). При этом, в скомпилированном машинном коде кешируется некоторое ограниченное (например 5) число найденных методов. Скомпилированный код при этом может выглядеть так:

      if (object->class == #A) goto #A::m;
      if (object->class == #B) goto #B::m;
      goto #system_lookup;


      Количество сравнений увеличивается только при необходимости, то есть для мономорфных точек вызова эффективность будет точно такая же, как при простом inline cache. Если список классов переполняется, то какой-то из наличных закешированных методов заменяется новым. То есть PIC значительно теряет в эффективности в мегаморфных точках вызова. Т.е. в точках где класс объектов меняется часто. Но, к счастью, таких мест незначительное количество. PIC перекочевал в современные виртуальные машины: Java, Visual Works Smalltalk, др.

      Технологии PIC уже почти 20 лет. Так что говорить о «медленности» виртуальных вызовов уже не модно. Хороший JIT компилятор должен уметь оптимизировать такие вызовы на лету.
      (по материалам smalltalk.ru)
      • 0
        а .net умеет?
        • +1
          да умеет, но только компилятор C# с его dynamic. советую почитать мою статью на эту тему.
          по-моему, здесь немного путают PIC (предназначенный для кэширования эквивалентных по своей сигнатуре методов в динамических языках) с виртуальными методами.
          если рассматривать статические языки, то для их виртуальных методов есть немного другие техники.
  • +4
    Ееееееееее, это прекрасно, если снова будет модно делать нативные приложения.
    А вообще, .NET не так уж и плох — его виртуальная машина не сильно уступает нативному коду (за исключением повышенного потребления памяти). И уж явно лучше стековой явы.
    • +1
      А в .net разве не стековая виртуальная машина?
    • –4
      «Лучше явы» по причине отречения от явовского принципа работы на многих, очень многих платформах. А когда я не могу нормально писать на С# под *nix — нафиг оно мне надо? Нет, конечно, если Вам не нужно ничего, кроме Win, то это безусловно лучший инструмент.
      • 0
        Можете. Mono вам в помощь.
        • 0
          И как оно с WinForms, м?
          • +2
            www.mono-project.com/WinForms

            Support for Windows Forms 2.0 is complete. At this point, we are largely just fixing bugs and polishing our code.
            • 0
              Спасибо, классно. Правда до меня доходили слухи со сложностью в отношении winforms на других платформах в смысле возможных притязаний microsoft.
    • +1
      боюсь вас огорчить, у .net нет виртуальной машины. промежуточный код компилится на лету в нативный.
      • +1
        O RLY? Я огорчен скорее тем, что есть такие комментарии.
        • 0
          ок. ступил. голова забита была всякими глупостями.
  • 0
    Автор путает LINQ выражения с лямбда-выражениями.
    • 0
      Прочитал в оригинале(кстати, почему нет ссылки на него?), тоже ничего не понял, почему он предлагает синтаксический сахар для делегатов, взамен не имеющей к ним отношения функциональной части языка.
      Опять же синтаксис есть и так, то есть можно написать var a = B, где B это, например void B(){} такой метод класса.
      Не хватает не синтаксиса, а его имплементации — компилятор ругается, что нельзя это делать implicitly, ибо автоматически тип делегата не создается (что, если я не напутал, автор предлагает реализовать, попутно упомнув всуе wpf), его надо декларировать самостоятельно.
      • 0
        Я так понял, что он не только про методы говорит, а про свойства также например, на них действительно нельзя сделать ссылки без создания делегатов, которые возвращали бы их значения. А ссылка на оригинал есть в стандартном месте (не знаю как точно называется, панель под статьей).
      • 0
        Ссылка на оригинал находится там же, где и у всех остальных топиков-переводов на хабре — имя автора в панели под постом.

        Что касается предлагаемого автором синтаксиса, то тут скорее имелись в виду не ссылки на методы и свойства для их вызова, а специальные конструкции вроде атрибутов, которые можно использовать в метапрограммировании. Т. е. symbol myMethod — это не делегат и даже не MethodInfo, а нечто новое, что например можно использовать для анализа или генерации кода во время JIT компиляции. Это позволит заменить строки с названиями свойств в реализации INotifyPropertyChanged на строготипизированные ссылки на свойства, проверяемые во время компиляции. Также такие ссылки можно использовать в сценариях, в которых сейчас используются PropertyInfo, FieldInfo и прочие MemberInfo из System.Reflection. Ну и теоретически производительность подобных символов должна быть по-лучше отражения, где-то на уровне делегатов в последних версиях .net.

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