суббота, 26 ноября 2011 г.

[prog.thoughts] Что native, а что не native?

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

В частности, довольно долго участники спора противопоставляли native-приложения managed-приложениям. Но когда дело дошло до выяснения того, чем же native отличается от не-native, ничего путного родиться не смогло (вероятно, тот ламер, который больше всех верещал о доминировании managed, слабо разбирается в этом вопросе, а его более матерые собеседники откровенно стебались и не спешили просвещать человека). Хотя вопрос, как мне думается, не так прост, как может показаться. Я и сам бы с ходу не смог сформулировать что есть native, а что managed.

Когда я в бытность активным RSDN-ером бодался с .NET-евангелистами все казалось просто: .NET и JVM – это managed, С/C++ – это native, Python/Perl/Ruby/PHP/Bash и пр. – это managed, Objective-C – это native и т.д. Вроде бы все интуитивно понятно. Но, как показал упомянутый RSDN-овский флейм, интуиция может быть у каждого своя. Поэтому нужно придумать что-то более-менее формальное.

Так вот, мне представляется, что native-приложение – это такое приложение, для запуска и работы которых достаточно только штатных возможностей ОС и которое работает на “голом железе” (т.е. инструкции приложения сразу же выполняются процессором, а не какой-либо виртуальной машиной). А вот для managed-приложения требуется некий промежуточный слой между кодом приложения и ОС. Таким слоем может быть либо интерпретатор (как в случае со скриптовыми языками вроде Python/Perl/Ruby), либо виртуальная машина (JVM), либо JIT-среда, которая компилирует инструкции VM в нативный код при первом обращении (как в .NET).

Вот такое вот простое разграничение. Никакие сборщики мусора, никакие средства трассировки и контроля за исполнением (вроде проверок выхода за рамки массива), никакие средства рефлексии и предоставления метаинформации о коде в расчет не принимаются. Просто потому, что есть примеры вполне себе native-приложений, у которых есть и GC, и контроль за кодом, и подробная диагностика мест возникновения исключений, и прочая лабуда. Например, у разработанных на Eiffel, OCaml, D или Go приложений.

При этом нужно говорить именно о приложениях. А не о коде. И уж тем более не о языках программирования. Просто потому, что один и тот же язык может иметь транслятор как в native-код, так и в код какой-либо виртуальной машины. Как у Eiffel или OCaml, например. И один и тот же код может работать как в native-, так и в managed-приложении. Хотя, если код затачивается под использование возможностей конкретной managed-платформы, то тогда имеет смысл называть код managed-кодом.

Но самое забавное, что даже такие, казалось бы, низкоуровневые языки, как C++ и C, имеет интерпретаторы! Пусть поддерживающие ограниченное подмножество языков, но тем не менее позволяющие запускать довольно-таки серьезные приложения. Первый из них – это CINT. Второй – Ch. Вот такие дела, и C++ приложения могут быть вполне себе managed. По крайней мере согласно моему определению ;)

13 комментариев:

Andrey Valyaev комментирует...

Помоему managed - это не совсем интерпретируемый, это как это выразиться - контролируемый код.

А сейчас помоему настолько все перемешалось, что чистых приложений вообще нету. :)

В той же java есть JNI, который позволяет обоюдно взаимодействовать java и c++ коду. Это ведь одно приложение... :)

Чисто объектно-ориентированное приложение! вымысел или реальность? :)

eao197 комментирует...

Так поэтому я и сделал акцент на то, что нужно для старта приложения -- если только средства ОС, то нативное. Если что-то еще -- то управляемое. А уже как работает управляемое (интерпретацией или полным JIT-ом) это уже не суть.

Что до ООП, то зависит от языка реализации. Если это Smalltalk, Eiffel или Ruby -- то есть чистое ООП.

night beast комментирует...

возникает вопрос, а надо ли все делить на натив и менеджет?
если надо, то какая от этого польза.

eao197 комментирует...

@night beast:

Хороший вопрос. С точки зрения разработки ПО, наверное, найдется совсем не много областей, где имело бы смысл делать такие оценки. Например, встраиваемое ПО. Поскольку там разница между native и managed может давать разную вычислительную нагрузку и, как следствие, разные требования к ресурсам и энергопотреблению.

Но с точки зрения форумных священных воин имеет смысл четко обозначить границы. Чтобы объяснять красноглазым фанатикам той или иной технологии, что native -- это не обязательно растрел или утечки памяти. Т.е. есть смысл во вразумлении и обучении уму-разуму :)

night beast комментирует...

Дык, стоит ли тратить свое время на фанатиков.
Пусть себе тешат ЧСВ.
Даже если и убедишь в чем-то (что маловероятно), толку от этого будет немного. Люди не любят признавать свою неправоту. А уж в терминологических спорах, так темболее. Вот :)

имя комментирует...

действительно, сложно сказать что такое native, даже как противопоставление managed

ну можно предположить, что бинарник, полученый после компиляции managed-кода, будет гарантированно не вылезающим за границы массива, не переписывающим адрес возврата и т.п. (компиляция может быть JIT или AOT)

однако, верификация бинарного кода (типа как в NaCl) может дать тот же, и даже более надежный, результат

в общем, кмк, нужны какие-то более точные и тонкие характеристики, вместо native как противопоставление managed

Unknown комментирует...

Я вижу разницу примерно так: если программист может предсказуемо влиять на ассемблерный код, на то что собственно выполняет процессор - то это native, если нет - то нет. Например семантика индексации в массивах и операции с указателями в C[++] делают их native. Проблема только в том, что процессоры и ассемблеры уверенно движутся к тому, чтобы стать абстракцией.

Насчёт дискусси на RSDN - в таких флеймах всегда умиляет полное отсутствие контекста. На чём лучше написать абстрактно-сферичное приложение в вакууме? Мне вот всегда казалось, что его просто нафиг не нужно писать.

eao197 комментирует...

@CheatEx:

С влиянием не так просто. Несколько лет назад я видел статейку, в которой описывалась ситуация с Java. Программу запустили на новой версии JVM и она стала резко тормозить. Для того, чтобы найти причину разработчикам пришлось опуститься на уровень машинного кода. Там выяснилось, что две обновляемые разными потоками переменные в этой версии JVM оказывались очень близко в памяти. И для доступа к ним использовалась одна и так же cache line. Соответственно, конкуренция между потоками за эту cache line и была причиной тормозов. Я не помню, как именно они разнесли затем переменные в памяти, но им явно пришлось при программировании на Java влиять на низкоуровневые детали.

С другой стороны, многие математики программируют на Pascal или Фортран так, что даже не задумываются о том, что обращения к элементам массива в Pascal -- это почти то же самое, что и в C[++].

Unknown комментирует...

Ну это хак, долговременный эффект от которого никак не гарантируется спецификацией (равно как и его появление в ней не предусмотрено). Это из тех дыр в абстракциях которые всё-равно вылезают наружу, а не её часть.

Хотя да, это ещё один намёк на то, что граница native - managed она для личного комфорта а не от реального положения дел.

eao197 комментирует...

@CheatEx:

>Ну это хак

Скорее не хак, а напоминаие о том, что так только приходится бороться за какие-то реальные ресурсы, так сразу разработчик из высот воздушных замков вынужден спускаться на землю. Вне зависимости от native/managed.

>граница native - managed она для личного комфорта а не от реального положения дел.

Да, что-то типа того. Есть удобный для тебя способ классификации, но не более.

имя комментирует...

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

да, и на эту тему у меня сплошной мат!!!

хотя, впрочем, есть надежда, что там будет возможность залезать внутрь этой абстракции и делать так, как *тебе* надо

то есть я за VLIW

имя комментирует...

еще на тему "ассемблер как абстракция" -- даже сейчас можно например запретить кэшировать прочитанную и записанную память

дальше наверно будет возможность занять определенную часть кэша определенной частью памяти, а может что еще полезное придмают

имя комментирует...

напоминаие о том, что так только приходится бороться за какие-то реальные ресурсы, так сразу разработчик из высот воздушных замков вынужден спускаться на землю. Вне зависимости от native/managed.

и native тут имеет явное преимущество в том, что когда тебе вдруг потребуется какое-то нестандартное managed, ты можешь сам его изготовить... вот только, к сожалению, система типов у с++ слаба для того, чтобы потом изготовленное не разрушить