Comments 171
Базовые сущности: Integer и Float вот и все, что должно быть, детали пусть рулит компилятор.Вы предлагаете компилятору всегда использовать максимальный тип (long и double в случае Java) или вычислять необходимый размер анализируя код? В первом случае у нас будет неэффективное использование памяти и просадка по производительности (особенно на 32х битных системах), а во втором риск переполнения и/или увеличение времени компиляции.
в рантайме это вполне возможно
Покажите хоть один язык, где это возможно и при этом эффективно?
Проблема в том, что числа не одинаковые. И плавающая точка ни разу не замена целым числам. И число произвольной точности практически не реально реализовать так, чтобы это было также эффективно, как числа, укладывающиеся скажем в 128 бит. Не можете вы этим не загружать мозг.
Насчет эффективности, я специально запрофилировал getDistance в моих тестах, где происходят самые интенсивные вычисления с плавающей точкой и Ceylon показал результат лучше чем Kotlin, но хуже чем Java.
Мое мнение что если такой класс реализован достаточно эффективно в 99% случаев можно не парится и использовать его. Но, конечно, если на финальной стадии при профилировании обнаруживаются узкие места, тогда уже есть смысл начать что-то оптимизировать.
практический смысл.
Я то как раз прекрасно понимаю что я измеряю и как, если ты чего-то не понял из статьи — спрашивай, начнем нагружать тебе мозг :)
Если хочешь предложить что-то конкретное, предлагай — рассмотрим.
P.S. с теми кто обращается на Вы я тоже на Вы, с теми кто на ты, тоже на ты, так что без обид :)
Смотри например: msdn.microsoft.com/en-us/en-en/library/system.io.streamreader.discardbuffereddata(v=vs.110).aspx
Во-первых, я не ставил перед собой целью исследовать исходники библиотек ввода-вывод и сравнивать сколько они там байт себе под буфера выделяют.
Во-вторых, первичная буферизация при чтении все равно происходит в драйверах/системе, а вторичная будь то 128 или 4096 байт может не дать существенного эффекта (как и показал эксперимент).
Не совсем в тему, но помню, что, например, игра с флагами FILE_FLAG_RANDOM_ACCESS и FILE_FLAG_SEQUENTIAL_SCAN для нативного Windows API CreateFile оказывают значительное влияние на скорость чтения.
Добавил BufferedStream в C# реализацию и проверил на небольших файлах, погоды он не делает, разница 10-15ms.
Но все равно добавлю в код, спасибо за совет :)
P.S. Вы сами признаетесь, что являетесь профессионалом в Java. Написание кода на языках, которые вы знаете не так хорошо, может содержать неэффективные решения. Особенно меня настораживает проигрыш в 1.5-2 раза кода на С++.
Просто в JVM ввод-вывод лучше оптимизирован чем в Qt, вот и все — никаких чудес.
P.S. ты давай там завязывай с тапкапи общаться, так и до дурки недалеко :)
Вот исходники: drive.google.com/open?id=1N3sEsw4MZ33GI-PPQOw_vocahGdjg9bq
Вот тулза mp2dcf (набросал на Kotlin за час :) ), которая конвертирует карты в «польском» формате в DCF: drive.google.com/open?id=12SlixUmpnrKH5Eh8k69m_T1tmWCVy6Ko
Карты можно скачать например тут: navitel.osm.rambler.ru
Я успел попробовать на Италии: navitel.osm.rambler.ru/?country=Italy
QMAKE_CFLAGS_RELEASE = -O3 -march=native -mtune=native
для Qt?
Я вообще старался не пользоваться какими-то специфичными трюками конкретного языка чтобы не создавать ему преференций.
выбирая профиль Release я уже и так явно выразил свои намерения и «подписался» под производительностью
Нет. Вы подписались под некоторой минимально-безопасной степенью оптимизации.
А если пользователю после этого нужно все-таки лезть в настройки и прописывать какие-то дополнительные ключи, это недоработка среды/билдсистемы.
Снова нет. Это гибкость, которая нужна только тому, кому она на самом деле нужна.
Взять хотя бы "-march=native -mtune=native" — это уже нарушение одинаковых условий для всех, ведь JVM не был скомпилирован конкретно для моей машины.
я сравниваю производительность языков в их дефолтной конфигурации. Для Qt это Release.
Взять хотя бы "-march=native -mtune=native" — это уже нарушение одинаковых условий для всех, ведь JVM не был скомпилирован конкретно для моей машины.
Абсолютно некорректное сравнение.
Неважно под какую машину была скомпилирована Java, всё равно её JIT-компилятор скомпилирует ваш код под конкретно ваш компьютер (если вы прямо не запретите ей это ключами).
C++ же язык статический, он применяет оптимизации не в процессе работы программы, а в процессе компиляции.
Так что сейчас вы установили, что для очень простых программ максимальная оптимизация HotSpot работает лучше чем средняя C++ компиллятора.
Что и так очевидно.
Так как С++ компилятор используется в самых различных вариантах оптимизации (от дебага, до полного инлайна всех функций с разворотом всех циклов), то как дефолтный принят некий средний уровень.
И если уж вы пользуетесь этим компилятором, то и настраивайте его соответственно.
Повторюсь, компилятор настроен профилем Release — точка. И у меня нет желания прогонять его с десятками разных ключей для GCC или Microsoft Compiler-а и выбирать лучший вариант для C++. Как настроили разработчики — так и поехало.
Предлагаю завершить на этом дискуссию, если вам интересно с O3 — исходники в вашем распоряжении, проверяйте, делитесь результатами.
Повторюсь, компилятор настроен профилем Release — точка.
Ваше право.
Только статья тогда должна называться: «Проверка дефолтных настроек различных языков, технологий, компиляторов и реализаций потоков данных».
Для производительности — только прямое чтение.
Не понял, о чем статья: JVM works well — К.О. Но за счет памяти. Еще на ней можно писать парсеры. Всё.
Нужны другие тесты.
P.S И код лучше выкладывать на гитхаб — удобнее смотреть, да и может коммитеры подтянутся — исправят ошибки, например.
Во-вторых, для языков с JVM подсистема ввода-вывода особой роли как раз не играет, т.к. используется из Java, а результаты тем не менее существенно различаются.
Так что здесь, всего лишь, сравниваются производительность языков на JVM и тесты на мой, естественно, субъективный взгляд вполне адекватные и показательные :)
Кому нужны другие тесты могут проделать эту работу самостоятельно и поделиться результатом, с большим интересом почитаю :)
P.S. на гитхаб выложу на досуге, может и правда блох наловим в коде :)
Только зачем? Мне интересно было сравнить пользуясь стандартными средствами языка, если его библиотека I/O плохо оптимизирована эту уже минус.
Бинарь получившийся на выходе обычно измерялся мегабайтами.
Сравниваете тёплое с мягким. *.class получается сравнительно небольшим, но для его запуска нужна отдельная программа. Бинарник на Rust получается 500Кб, что много, если не думать о том, что он сам же и обеспечивает уборку за собой.
Можно относительно честно сравнить размеры компилируя всё статически (и даже здесь будет чувствоваться влияние разных ОС и архитектуры системы под которую собираем). Но даже сравнивая эти цифры, довольно сложно сделать какие-то выводы наверняка.
Ну а профессиональные (и адекватные :) ) комментарии к коду только приветствуются.
String str = null; // Ошибка компиляции, тип не поддерживает null
— String? str = null; // OK.
str.length() // Ошибка компиляции (не рантайма!)
Это может отловить кучу проблем на раннем этапе.
Задавая Optional вы одновременно указываете тип обьекта, который он может содержать. И с этого момента компилятор помогает Вам.
Мой опыт по использованию Optional очень позитивный.
Осмелюсь предложить Вам почитать вот эту серию статей.
первые опыты писания программ на новом языке могут привести к неэффективному коду, который профессионал может улучшить в несколько раз.
Это лишает статью смысла, ведь в ней сравнивается производительность. Методика сравнения описана общими словами, а код вообще не сразу появился, а когда появился — в комментариях, в виде архива в облаке. То есть, имхо, работа сделана как попало, статья оформлена как попало.
Плохая статья — плохие оценки, все логично. Но, кмк, это должно мотивировать автора совершенствовать навыки, а не обижаться и замыкаться в себе. Эго отращивать вредно, а на качество жизни рейтинг хабра не влияет.
Кому-то будет интересно, кому-то нет, это нормально.
Код постараюсь выложить на гитхаб если он станет для Вас лучше от этого :)
А судить о качестве статьи по тому где выложен код, это как-то… странно :)
А судить о качестве статьи по тому где выложен код, это как-то… странно :)Согласитесь, услышать про джаву, которая в очередных синтетических тестах чудным образом обогнала натив и не найти пруфы — это не менее странно.
Информация интересная, если принять её на веру. Но все тут люди опытные, к информации относятся критически и для многих (например для меня) множество пассажей выглядят очень сомнительными, как и полученные результаты. Статьи содержащие сомнительную информацию минусят, и это правильно.
Тем более я посмотрел, это самая первая статья автора.
Но это моё личное мнение. Я никому её не навязываю.
Разумеется, если нет понравившихся комментариев, то и плюсики ставить некуда. Тогда может стоить подумать что в статье не понравилось и свой комментарий написать.
Может лучше поставить плюсики за понравившиеся критические комментарии?
Для этого можно поставить плюсик конкретным критическим комментариям. А ставить оценку именно статье за комментарии в ней – ну это как минимум странно.
Может лучше поставить плюсики за понравившиеся критические комментарии?
Перечитал эту фразу. Теперь сижу и думаю, что я дебил. Я вот её расценил почему-то сначала как "поставить + статье за комментарии". Извиняюсь за свой мозг, который почему-то таким образом информацию воспринял.
Конечно, чтобы мнение было непредвзято, было бы здорово не видеть текущую оценку, до момента «голосования» или истечения срока голосования. Мне попадалось исследование, по итогу которого был сделан вывод, что люди ставят более охотно оценку которая совпадает с большинством. Но если не показывать текущую оценку статьи это может поломать систему, по которой статьи отбираются и показываются в лучшем. Так как если ты читаешь статью из лучшего — значит у нее высокая оценка, хотя ты не знаешь, может быть все статьи за выбранный период имеют отрицательную оценку. :) Так что, может быть, сокрытие оценки и было бы полезным.
чтобы мнение было непредвзято, было бы здорово не видеть текущую оценку, до момента «голосования» или истечения срока голосованияА как же хайп вокруг сильно заплюсованных/заминусованных свежих статей?) ТМовцы не с проста спрашивали об этом не так давно.
Кмк, неплохо было бы показывать градиент оценок за некотороый крайний отрезок времи, а не абсолютное значение.
например вместо
mSegments.contains(segment.getClustId())
нужно использовать find для получения идентичного поведения
Объекты вы передаёте копиями — зачем? Можно по ссылке(как в джаве) или move. Я думаю это не все, но с телефона смотреть не удобно.
Вообще, я вроде старался активно использовать константные ссылки где можно. Возможности по перемещению из C++11, действительно не использовал.
Да, это может существенно повлиять на результаты. Например, взять небольшой фрагмент кода из performer.cpp
:
if (mSegments.contains(segment.getClustId())) {
mSegments[segment.getClustId()] << segment;
} else {
QList<DcfSegment> list;
list << segment;
mSegments[segment.getClustId()] = list;
}
Во первых, два поиска по мапу вместо одного (про это уже сказали). Но наиболее характерный код из ветки else
, очень характерный для Java и ужасный для C++. По таким моментам очень легко заметить, что вы обычно пишите на Java и плохо разбираетесь в C++. Для джавы код вполне логичен — вы создаёте новый список и помещаете его в мап. Однако в C++ это будет выполняться так: вы создаёте сначала временный экземпляр класса, кладёте в него элемент, потом создаёте ещё один список внутри хэшмапа, присваиваете локальный список тому, что находится в хэшмапе, при этом по новой происходит выделение памяти в хипе и копирование всего содержимого (пусть это даже всего один элемент), после чего локальная копия уничтожается с освобождением памяти. Итого, у вас лишние поиски по хэшмапу, лишние копирования, и лишние операции с памятью, которые достаточно дорогие.
Но важнее всего то, что здесь вообще не нужен if и ветвление. Создание нового списка происходит при вызове оператора []
. Плюсовик написал бы вместо всего этого одну строчку, которая при этом и работала бы быстрее:
mSegments[segment.getClustId()] << segment;
Если QHash не содержит ключа он создаст объект по дефолтному конструктору, что в нашем случае собственно и нужно. Хорошо поправлю, но не думаю что это существенно повлияет на результат. Потому что я проводил подобный эксперимент на Kotlin-е, делал сначала проверку ключа, потом подкладывал — на больших тестах разница была порядка 40-50ms.
QHash
, кстати, тоже в хипе.на хипе здесь ничего создаваться не будет, все на стеке."
QList will allocate its items on the heap unless sizeof(T) <= sizeof(void*)
"
документация | сорцы
Ну я исправил только этот момент и не стал смотреть дальше. Думаю, там есть ещё моменты в подобном ключе. Извините, но я не поверю, что правильно написанный плюсовый код медленнее, чем всё остальное.
QList<DcfSegment> list;
list << segment;
mSegments[segment.getClustId()] = list;
QList использует implicit sharing, поэтому фактического копирования коллекции в данном случае не будет. По эффективности этот код аналогичен коду на java.
Не писал под Qt, поэтому не знал этого нюанса. Спасибо за то, что просветили. Однако, интересно же, получается, Qt нарушает подход разделения функциональности. Список должен хранить. Если мне надо расшарить его я создам shared_ptr. А так, получается, нарушение основы плюсов — не платить за то, что тебе не нужно.
Всё ещё выглядит как функциональность, которой не должно быть в обычном списке. Видимо, так работают все QT-ые контейнеры? Выглядит как попытка сделать что-то вроде Java в плюсах — накладные расходы, о которых не просит пользователь, в надежде что он не выстрелит себе в ногу.
Не только контейнеры. Думаю в Qt много найдется вещей которые можно посчитать, как то о чем не просит пользователь, но это их право. Qt это не просто библиотека, это фреймворк, практически полностью самодостаточная система. При работе с Qt можно забыть о стандартной библиотеке и пользоваться только тем что предоставляет Qt. И них свой взгляд на управление ресурсами — подразумевается, что все по максимуму создается в кучи, а за удаление отвечает родитель.
Является ли это попыткой сделать "Java в плюсах" — не знаю, не знаком с Java, больше похоже на успешный кросс платформенный вариант C++ Builder. Это если уж искать какие-то аналогии. Но, думаю, лучше рассматривать Qt как самостоятельный фреймворк, со своими правилами и хорошими техниками.
Думаю тут дело в том, что выбор языка программирования это вопрос достаточно интимный, сродни выбору жены :), а при сравнении всем не угодишь, вот последователи разных языковых школ и размахались «минусовками». Ваш, коммент тоже, наверное, заминусуют :)
«Вашей кривизны» звучит как-то двусмысленно, будем считать, что это относится к коду :) я так же согласился что это косяк, но боюсь, что существенно на производительность это не повлияет (но надо будет проверить).
В Qt/C++ получились результаты такими какими получились, не вижу смысла там что-то менять, какая библиотека ввода — такой и результат.
Если кто-то напишет хорошую реализация на C++ можно добавить еще и ее для сравнения. Но меня больше интересовали языки с JVM.
C# (MSVC2015) — вошел в обзор только потому, что мне довелось написать на нем немалое количество строк, и никаких преимуществ по сравнению с Java я в нем не обнаружил.
Вы видимо хеловорды писали.
В сишарпе есть:
- свойства
- нулабилити
- екстеншн функции
- async/await
- имутабельность
- удобная вариантность <in/out T>
Интересно, как Вы сравнивали?
Из перечисленного Вами списка кое-чем пользовался: свойства, async/await, вариативностью. Еще там достаточно удобно форматировать строки $"".
Вы пишите:
никаких преимуществ по сравнению с Java я в нем не обнаружил.
и тут же, в коментарии, вы пишите:
кое-чем пользовался: свойства, async/await, вариативностью.
отсюда вопрос — где правда? Как можно пользоваться свойствами и не заметить этого?
Правда в том, что считать преимуществом, и это уже достаточно субъективно. Безусловно в C# есть свои приятные плюшки, но я не занимался их детальным сравнением в статье, а написал свои общие впечатления о C# в сравнении с Java. Ведь, как известно, на вкус и цвет товарищей нет, кому-то нравится C#, кому-то Java, кому-то Basic…
Ну Вы же пишите что:
никаких преимуществ по сравнению с Java я в нем не обнаружил
Я вам написал целый список преимуществ в сравнении с джава, вы говорите — да ими пользовался — я не понимаю логики. Вы не считаете это преимуществами?
Согласитесь что ваш список это тоже не абсолютная истина? Не все поголовно запишут это в преимущества. Кто-то скажет — свойства это круто! Кто-то нет. В той же Java можно реализовать часть этих фич через фреймворки если нужно.
Кто-то скажет — свойства это круто! Кто-то нет
Ну теперь мне все понятно :)
«Лично мне свойства не нравятся, и я был бы рад, если бы их поддержку убрали из Microsoft .NET Framework и сопутствующих языков программирования. Причина в том, что свойства выглядят как поля, на самом деле являясь методами.»
Джеффри Рихтер
ru.wikipedia.org/wiki/%D0%A1%D1%80%D0%B0%D0%B2%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_C_Sharp_%D0%B8_Java#%D0%A1%D0%B2%D0%BE%D0%B9%D1%81%D1%82%D0%B2%D0%B0
Как по мне так, например, такой достаточно типовой пример использования свойства в C#:
public string Foo { get; set;}
На Java можно записать просто
public String foo;
без накладных расходов на get; set; методы.
Если же мы решили запихнуть в get и set какую-то более сложную логику, то нам все-равно придется добавлять приватную переменную и тогда Java пара getter/setter будет не намного хуже.
public String foo;
Да, да, всех нас учили что нельзя шарить поле класса, только через методы доступа.
А вы когда-нибудь задумывались почему так нужно делать?
Основной аргумент как раз «академический», дескать нарушение инкапсуляции данных.
А что разве тупые геттеры/сеттеры, которые только возвращают и только присваивают его не нарушают?
В конце концов всем надоел этот шаблонный совершенно бессмысленный код и придумали свойства, чтобы это выглядело похожим просто на переменную.
И тут я не могу не признать резонность довода Джеффри Рихтер. Смотришь в код, на первый взгляд вроде бы выглядит как обычное присваивание, а потом идешь в сеттер свойства и мать чесная, там «Война и мир», кода вагон и маленькая тележка.
В более современных языках придумали «абстрактные атрибуты»:
Kotlin, Scala:
val foo: String
Да, здесь компилятором будут сгенерированы get и set, но по мне это ничем не хуже дедовского:
public String foo;
P.S. Насчет того, что учиться всегда полезно и никогда не поздно, готов полностью согласиться, очевидно вам тоже не повредит :)
нарушение инкапсуляции данных. А что разве тупые геттеры/сеттеры, которые только возвращают и только присваивают его не нарушают?
Нет, не нарушают. Клиент ничего не знает об имплементации аксессоров. Свойства могут декларироваться в интерфейсах и быть виртуальными.
Это всё выливается в то, что при изменении логики аксессоров даже не нужно перекомпилировать клиентские сборки, не говоря уже о необходимости грепать по исходникам клиента, чтобы воткнуть обёртку в каждом месте использования.
без накладных расходов на get; set; методы.Методы могут инлайниться компилятором.
В более современных языках придумали «абстрактные атрибуты»:
Kotlin, Scala:
val foo: String
Да, здесь компилятором будут сгенерированы get и set, но по мне это ничем не хуже дедовского:
public String foo;
хуже, там приватное поле, и аксессоры (в вашем примере только геттер)
Для начала сразу же повеселила фраза «Т.е. маленькая програмулька, которая печатает в консоль тупую строчку и должна занимать от силы 3-4Кб весит мегабайты!» Ну так оно и весит мегабайты на практически всех языках, кроме разве что чистого C++. В той же Java это будет более 100 мегабайт (мы же будем по честному считать, включая рантайм, не так ли?). Причём эта фраза была в статье не просто так, а на её основание из тестирование убрали как раз самые интересные и перспективные языки.
На фоне предыдущего пункта меня сильно поразило наличие в тестирование C++/Qt, т.к. как раз Qt и является примером очень жирной библиотеки — тут было явно что-то не то. Но когда я увидел размер программы на Qt в 37 КБ, то всё стало на свои слова — автор похоже ещё и не особо разбирается в разнице между статической и динамической линковкой…
Так же слегка шокировали слова «обычные язык, без откровений» по отношению к Scala. И это про язык, который принёс полноценное функциональное программирование и метапрограммирование в мир JVM.
После всего этого на результаты тестов уже можно было и не смотреть особо… Гораздо интереснее было взглянуть на исходники. И в первую очередь на вариант с C++. Собственно как и ожидалось, там был классический «java стиль», тот самый, который не позволяет писать быстродействующее ПО на C++. Если же решить эту простейшую задачку на нормальном современном C++ (и для начала это будет Boost, а не Qt), то она будет и в разы быстрее и в разы меньше кода.
В итоге статье крайне не понравилась огромным числом ляпов, не говоря уже о смешных итоговых результатах.
Посмотреть бы в глаза тому человеку, который эту статью заапрувил.
Мда… Мне ещё не приходилось писать столько отрицательных комментариев, к статье с вроде как правильной изначальной идеей — такого уникально низкого уровня реализации я давно не видел.
Ну это Ваша, абсолютно субъективная точка зрения совершенно ничем не подкрепленная. На это можно ответить только что-нибудь типа «я давно не видел комментария с таким высоким уровнем предвзятости и фанатизма».
Для начала сразу же повеселила фраза
Ну ладно хоть развеселило, но по мне так это грустно.
Во-первых, JVM бывают разные, есть очень маленькие.
Во-вторых, в JVM логика программы четко отделена от рантайма языка.
В-третьих, JVM портирован почти везде, так что можно считать его частью системы.
Раз уж это моя статья позвольте мне и решать кого записывать в перспективные. Напишите свою — с удовольствием почитаю.
На фоне предыдущего пункта меня сильно поразило наличие в тестирование C++/Qt, т.к. как раз Qt и является примером очень жирной библиотеки — тут было явно что-то не то.
На мой взгляд, красота и удобство Qt API в сравнении с убогой std в разы перевешивают возможные потери производительности.
Но когда я увидел размер программы на Qt в 37 КБ, то всё стало на свои слова — автор похоже ещё и не особо разбирается в разнице между статической и динамической линковкой…
А мне кажется что Вы слегка забываетесь и переходите на личности. Как я уже писал в Qt я использовал дефолтный профиль Release ничего не меняя. И Qt, естественно, использовал динамическую линковку, это нормально и правильно.
Так же слегка шокировали слова «обычные язык, без откровений» по отношению к Scala. И это про язык, который принёс полноценное функциональное программирование и метапрограммирование в мир JVM.
За функциональное программирование в статье ничего не было. Мне как-то Haskell-а вполне хватает.
Собственно как и ожидалось, там был классический «java стиль»
Да нет там никакого «Java стиля» обычный Qt-шный код.
Если же решить эту простейшую задачку на нормальном современном C++ (и для начала это будет Boost, а не Qt),
Код в студию, пожалуйста, только не в С-style.
Раз уж это моя статья позвольте мне и решать кого записывать в перспективные.
Это немного не так работает.
Ну и мы, как аудитория, в праве писать (любые) комментарии и (негативно) оценивать статью.
Во-первых, JVM бывают разные, есть очень маленькие.
Меньше получаемого в Rust/D/Nim исполняемого файла под той же платформой? )
В-третьих, JVM портирован почти везде, так что можно считать его частью системы.
Похоже кто-то тут путает кроссплатформенность (имеется не только у JVM, а много где, включая и Rust/D/Nim) и предустановленный в данной ОС рантайм. Я что-то не слышал про предустановленный рантайм Java на Windows или OSX или Linux…
Раз уж это моя статья позвольте мне и решать кого записывать в перспективные. Напишите свою — с удовольствием почитаю.
Выбирать критерии отбора языков — это безусловно авторское дело. Однако, даже если использовать для этого такой странный по нынешним временам (если конечно речь не про МК) параметр, как размер получаемого дистрибутива, то всё равно это надо делать честно (учитывая весь рантайм). Именно это один из главных недостатков статьи, просто бросающийся в глаза своей некорректностью.
На мой взгляд, красота и удобство Qt API в сравнении с убогой std в разы перевешивают возможные потери производительности.
Ха, совсем неудивительна симпатия Java-программиста к Qt. Только вот надо понимать, что это совсем не путь развития современного C++. Qt родилась в 90-ые (как раз одновременно с Java) и вся её архитектура из тех времён. Сейчас мир C++ уже далеко ушёл от этого в совсем другую сторону и данный Java-стиль является откровенным legacy. Конечно авторы Qt понемногу пытаются исправить эту ситуацию, но пока выходит очень слабо.
Да нет там никакого «Java стиля» обычный Qt-шный код.
)))
Код в студию, пожалуйста, только не в С-style.
Накидал сейчас для развлечения на нормальном C++ (с Boost'ом вместо Qt) программку с полностью аналогичной функциональностью. Значит получился один файл исходников из 70 строк/2,4 КБ, причём 1/3 файла занимают подключения заголовочных файлов и пространств имён. Исполняемый файл при полной (включая стандартную библиотеку языка, т.е. такой exe можно спокойно распространять везде в одиночку) статической линковке на 64-ёх битной Windows занимает 1 МБ. Время работы в 1,5 раза меньше, чем у приведённого в статье Java кода, что в общем то и ожидалось изначально.
Отрадно что человек сел и написал код, все лучше чем слюной брызгать :)
Ежели он его еще и опубликует и он окажется адекватным, я добавлю его в тесты и будет у нас полный комплект: современный C++ :)
P.S. Вероятно, товарищ начитался Скотта Майерса, раз уж про «современность» древнего C++ заговорил :)
Кстати, как раз благодаря просмотру кода на разных языках неожиданно (изначально я этого не заметил) оказалось, что автор статьи ещё и смухлевал немного — код разный (принципиально, а не из-за особенности языка) на разных языках. Детали опишу в другом комментарии (ниже).
Значит получился один файл исходников из 70 строк/2,4 КБ, причём 1/3 файла занимают подключения заголовочных файлов и пространств имён.
Зачем описывать словами, когда можно просто показать код?
Меньше получаемого в Rust/D/Nim исполняемого файла под той же платформой? )
Исполняемый файл будет больше чем jar, но зато в нем будут все «кишки» языка :) если прибавить рантайм Java то он будет весить больше.
Вам самому-то не надоело это муслоить? :) Вроде бы очевидные вещи.
Совершенно не хочется пересказывать ту часть статьи другими словами — кратко «жирные» бинари на мой взгляд это не эстетично, думаю тут есть простор для оптимизации, не более того. А вышеупомянутые языки отсеялись по многим другим факторам, в частности:
Похоже кто-то тут путает кроссплатформенность (имеется не только у JVM, а много где, включая и Rust/D/Nim) и предустановленный в данной ОС рантайм.
А похоже кто-то очень любит поумничать :) ну да ладно все мы тут не без греха :)
Думаю что JVM портирован на большее количество платформ чем тот же Nim и Rust — это кроссплатформенность. Да и со стабильностью в JVM все будет почетче.
Сейчас мир C++ уже далеко ушёл от этого в совсем другую сторону и данный Java-стиль является откровенным legacy
Спорное утверждение, дизайн проверенный временем доказал свое право на существование.
Накидал сейчас для развлечения на нормальном C++
Отлично, код в студию! :)
Исполняемый файл будет больше чем jar, но зато в нем будут все «кишки» языка :) если прибавить рантайм Java то он будет весить больше.
Вам самому-то не надоело это муслоить? :) Вроде бы очевидные вещи.
Если это действительно очевидные вещи, то тогда солидный кусок обсуждаемой статьи надо бы выкинуть… )))
Совершенно не хочется пересказывать ту часть статьи другими словами — кратко «жирные» бинари на мой взгляд это не эстетично, думаю тут есть простор для оптимизации, не более того.
Это уже не инженерные аргументы, а какие-то личные фобии.
Думаю что JVM портирован на большее количество платформ чем тот же Nim и Rust — это кроссплатформенность. Да и со стабильностью в JVM все будет почетче.
Вообще то Nim компилируется в C++ (который априори более кроссплатформенный, чем любые обсуждаемые тут языки). А что касается Rust'а, то например это второй язык (после C++), который имеет возможность написания кода для платформы WebAssembly (будущее нагруженного web'a), что является недостижимым для JVM в данный момент.
Спорное утверждение, дизайн проверенный временем доказал свое право на существование.
Любители Кобола говорили также… )))
Отлично, код в студию! :)
Сейчас будет, но перед этим хочу заметить, что из-за создания своего варианта, я более внимательно посмотрел на представленные и заметил откровенные махинации. Странно что никто больше их не заметил. А именно, у класса DcfSegment (именно его экземпляры создаются миллионами в тесте) в Java реализации имеется функция getLength(), которая вычисляет длину сегмента при своём вызове (т.е. никогда в данном тесте) на базе значений конечных точек. В тоже время аналогичная функция из класса DcfSegment в C++ реализации возвращает значение поля mLength (которого вообще нет в Java реализации), которое вычисляется в конструкторе класса. Т.е. в C++ варианте не только имеем лишнее поле, но и дополнительные тяжёлые вычисления при каждом конструирование такого объекта. И это называется тестом производительности? Скорее похоже на откровенную махинацию…
Ну а что касается варианта на современном C++, то выкладывать весь проектик на какие-то ресурсы мне лень, так что кину исходник прямо в этом комментарии (обрезав инклуды с неймспейсами, чтобы покомпактнее было):
constexpr double R=5000.0;
struct position{
double lat;
double lon;
};
double distance(const position& p1, const position& p2)
{
const double sin_lat=sin((p2.lat-p1.lat)*M_PI/360.0);
const double sin_lon=sin((p2.lon-p1.lon)*M_PI/360.0);
const double a=sin_lat*sin_lat+cos(p1.lat*M_PI/180.0)*cos(p2.lat*M_PI/180.0)*sin_lon*sin_lon;
return 2.0*atan2(sqrt(a), sqrt(1.0-a));
}
struct segment{
position begin;
position end;
};
unordered_map<string, list<segment>> segments;
void on_new_segment(const segment& s, const string& id)
{
static position p=s.begin;
if(distance(p, s.begin)<R||distance(p, s.end)<R) segments[id].push_back(s);
}
void on_error(const string& s) {wcout<<"Invalid DCF line: "<<s<<endl;}
int main(int argc, char *argv[])
{
auto_cpu_timer timer;
if(argc<2) return 1;
error_code ec;
for(directory_iterator i(argv[1], ec), e; i!=e; i++){
if(!is_regular_file(i->status())||i->path().extension()!=".dcf") continue;
wcout<<"Processing '"<<i->path().filename()<<"'..."<<endl;
mapped_file_source file(i->path());
double lat1, lon1, lat2, lon2;
string id;
parse(file.data(), file.data()+file.size(),
*(("SEG:">>double_[ref(lat1)=_1]>>':'>>double_[ref(lon1)=_1]>>':'>>double_[ref(lat2)=_1]>>':'>>double_[ref(lon2)=_1]>>':'>>
*("ClustID:">>(+(char_-eol-':'))[([&](auto& s){id={begin(s), end(s)};})]>>':'|+(char_-eol-':')>>':')>>eol)
[([&]{on_new_segment(segment{{lat1, lon1}, {lat2, lon2}}, id);})]|
("SEG:">>+(char_-eol))[([&](auto& s){on_error({begin(s), end(s)});})]>>eol|
+(char_-eol)>>eol));
}
wcout<<"Found "<<segments.size()<<" segments"<<endl;
}
Если это действительно очевидные вещи, то тогда солидный кусок обсуждаемой статьи надо бы выкинуть… )))
Размеры файлов и рантаймов вещи очевидные, а вот выводы которые я из них делаю это совсем другое, так что ничего выкидывать не будем :)
Это уже не инженерные аргументы, а какие-то личные фобии.
Недостаток оптимизации по размеру файла вполне себе аргумент, не знал что это фобия :)
Вообще то Nim компилируется в C++
Даже если он и компилируется в C++ давайте не будем забывать о жирном рантайме с кучей системных вызовов, без портирования их на новую платформу вы этот код не перенесете.
Любители Кобола говорили также…
Мало ли кто так говорил, от этого мысль не становиться хуже.
Сейчас будет, но перед этим хочу заметить, что из-за создания своего варианта, я более внимательно посмотрел на представленные и заметил откровенные махинации.
О, вот за то что обнаружили эту багу респект вам и уважуха! :) вот что значит когда от чесания языком люди переходят к делу. Это действительно существенное замечание.
Только попросил бы вас впредь быть поосторожнее с терминологией и избегать навешивания ярлыков типа «махинация». Это была большая небрежность с моей стороны, признаю, но в конце концов я именно для этого и выложил исходники чтобы все могли посмотреть и указать на ошибки.
Исправил и сразу прогнал тест на Debian-е: Java идет прямо вровень со Scala. Погоняю побольше, обновлю результаты.
Сейчас будет, но перед этим хочу заметить, что из-за создания своего варианта, я более внимательно посмотрел на представленные и заметил откровенные махинации.
Да и не надо утруждаться :) все равно это не годится. Смысл был в том чтобы на всех языках иметь одинаковую структуру приложения и классов. Чтобы затраты на создание и уничтожение классов тоже учитывались. Но за старания спасибо :)
Недостаток оптимизации по размеру файла вполне себе аргумент, не знал что это фобия :)
Если сравнивать статически скомпонованные нативные исполняемые файлы, то да, это нормально. К примеру если для решения одной и той же задачи статически скомпонованное приложение на C++ занимает 1 МБ, а на C++/Qt 7 MB, то вполне могут возникнуть вопросы об оптимизации Qt по данному вопросу. Однако если начинать сравнивать ещё и динамическую компоновку, причём беря в расчёт исключительно размер исполняемого файла (и наплевать, что рядом с ним валяется dll в 100 раз большего размера), то это уже становится чем-то из области психиатрии…
Это была большая небрежность с моей стороны, признаю, но в конце концов я именно для этого и выложил исходники чтобы все могли посмотреть и указать на ошибки.
И статья и исходный код отлично гармонируют между собой по наличию ошибок. Однако если относительно исходного кода вы их признаёте, то относительно самой статьи почему-то аналогичных выводов нет…
Да и не надо утруждаться :) все равно это не годится. Смысл был в том чтобы на всех языках иметь одинаковую структуру приложения и классов. Чтобы затраты на создание и уничтожение классов тоже учитывались. Но за старания спасибо :)
Хы, это же C++, язык основной концепций которого является нулевая цена абстракций. Можно навернуть там ещё хоть 150 классов типа Perfomer и от этого не только не поменяется производительность, но и даже не поменяется сам код (с точностью до бита) — компилятор просто выкидывает все эти лишние уровни абстракции в процессе оптимизации.
Ну и да, в любом случае не стоит применять архитектуру приложения происходящую из языков с навязанным ООП (типа Java, C# и т.п.) к полноценным мультипарадигменным языкам. Тем более, что современный C++ всё больше уходит от ООП в сторону функциональных стилей и т.п.
то это уже становится чем-то из области психиатрии…
Вы бы уже определились с амплуа в котором решили выступать :) если как психиатр, то могу лишь заметить, что ваши посты временами отдают маниакально депрессивным психозом :) (но, если серьезно, давайте уже заканчивать с этим флудом, лень время тратить).
Если все-таки как C++шник, то давайте попробуем дожевать так взволновавший вас вопрос своей мнимой некорректностью:
HelloWord в Qt, в дефолтном Release будет весить около 10Кб (динамическая линковка).
Ни в Nim-е, ни в Rust-е у вас даже близко не будет ни с динамической линковской, ни тем более в дефолтной конфигурации.
Т.е. очень много вспомогательного кода попадает в бинарь и, например, при любых исправлениях/обновлениях в системных функциях языка вам нужно будет перебилживать приложение.
Все это плохо, и это мое мнение.
Но, как я уже неоднократно писал, языки эти отсеялись по многим другим факторам, а совсем не только по размеру бинаря.
И статья и исходный код отлично гармонируют между собой по наличию ошибок. Однако если относительно исходного кода вы их признаёте, то относительно самой статьи почему-то аналогичных выводов нет…
Гармонируют… но разве что в вашем воображении :)
Все очень просто, реальные ошибки я охотно признаю, а всякие «фобии» сразу же идут в сад :)
Не следует упускать из виду очень простой факт: все адекватные замечания, которые здесь прозвучали, качественно не влияют на результат бенчмарков. Поэтому их ценность невелика.
Кроме вашего, это действительно важное замечание, моя ошибка позволила Java уйти вперед, но я это исправлю :)
Хы, это же C++, язык основной концепций которого является нулевая цена абстракций. Можно навернуть там ещё хоть 150 классов типа Perfomer и от этого не только не поменяется производительность, но и даже не поменяется сам код (с точностью до бита) — компилятор просто выкидывает все эти лишние уровни абстракции в процессе оптимизации.
Верите в добрый и могущественный Компилятор? Который вас всегда поймет, исправит все ошибки и сгенерирует самый современный и самый быстрый код на свете? :)
А в Деда Мороза верите? :)
Классы в C++ это вполне реальные, а не эфемерные сущности, они создаются, удаляются, для них вызываются конструкторы/деструкторы/методы. На все это тратится вполне конкретное машинное время, и компилятор далеко не всегда сможет выполнить эффективную оптимизацию.
Когда классы уже скомпилированы и положены, например, в динамическую библиотеку никакой оптимизации при использовании этой библиотеки (во время компиляции приложения) в вашем приложении уже не будет.
Если классы в статической библиотеке, то в общем случае тоже, разве что вы не пользуетесь компилятором от Intel с включенным IPO.
Ну и да, в любом случае не стоит применять архитектуру приложения происходящую из языков с навязанным ООП (типа Java, C# и т.п.) к полноценным мультипарадигменным языкам.
Я думаю что не стоит всерьез обсуждать «архитектуру» тестовых примеров. Понятно, что поставленную задачу можно решить гораздо проще. Фишка в том, что задача, которую они решают на самом деле фейковая. Нам интересно другое, насколько быстро они с ней справятся. Но тем не менее мне, все же, хотелось чтобы это хоть от части походило на реальное приложение.
Тем более, что современный C++ всё больше уходит от ООП в сторону функциональных стилей и т.п.
Мир все время куда-то движется, это не новость. Но никогда нельзя заранее сказать какие технологии приживутся, а какие отправятся в мусорный бак.
HelloWord в Qt, в дефолтном Release будет весить около 10Кб (динамическая линковка).
Ни в Nim-е, ни в Rust-е у вас даже близко не будет ни с динамической линковской, ни тем более в дефолтной конфигурации.
Ну а теперь посмотрим на реальность… Для примера возьмём скомпилированные для windows 64 бита приложения «hello world»:
C++ static: 832 KБ (exe) + 0 KБ (dll) = 832 KБ
C++ dynamic: 16,5 KБ (exe) + 1510,5 KБ (dll) = 1527 KБ
C++/Qt static: 4109 KБ (exe) + 0 KБ (dll) = 4109 KБ
C++/Qt dynamic: 17 KБ (exe) + 7378 KБ (dll) = 7395 KБ
D static: 565 KБ (exe) + 0 KБ (dll) = 565 KБ
Rust static: 2305 KБ (exe) + 0 KБ (dll) = 2305 KБ
Java dynamic: 0,4 КБ (class) + 158418,6 КБ (jre) = 158419 КБ
Я думаю из этих данных вполне очевидно преимущество статической линковки над динамической (конечно при условии, что у нас в итоговом приложение один exe файл), а так же реальная жирность Java и Qt решения.
Т.е. очень много вспомогательного кода попадает в бинарь и, например, при любых исправлениях/обновлениях в системных функциях языка вам нужно будет перебилживать приложение.
Все это плохо, и это мое мнение.
Вот бредовость этого мнения тут и обсуждается. Оно неверно потому, что даже если уж и принимать в расчёт занимаемое на диске место (хотя в наше время больших дисков и быстрого интернета это всё давно стало неактуальным), то это должен быть размер дистрибутива приложения, а не размер исполняемого файла.
Но, как я уже неоднократно писал, языки эти отсеялись по многим другим факторам, а совсем не только по размеру бинаря.
Никаких других внятных причин я в статье не увидел.
Классы в C++ это вполне реальные, а не эфемерные сущности, они создаются, удаляются, для них вызываются конструкторы/деструкторы/методы. На все это тратится вполне конкретное машинное время, и компилятор далеко не всегда сможет выполнить эффективную оптимизацию.
Когда классы уже скомпилированы и положены, например, в динамическую библиотеку никакой оптимизации при использовании этой библиотеки (во время компиляции приложения) в вашем приложении уже не будет.
Мы обсуждаем не абстрактный код в вакууме, а вполне конкретный тестовый пример. И моё конкретное утверждение о том, что если добавить в мою реализацию этого теста никчемные классы dcf_file и perfomer (остальные классы у меня присутствуют аналогично решению из статьи), то время исполнения теста не изменится. Есть желание оспорить это утверждение? )))
Если классы в статической библиотеке, то в общем случае тоже, разве что вы не пользуетесь компилятором от Intel с включенным IPO.
Вообще то это доступно во всех известных компилятора уже несколько десятилетий. ))) Только в остальных это называется LTO.
Я думаю из этих данных вполне очевидно преимущество статической линковки над динамической
Т.е. вы все это время всерьез препирались из-за того что лучше: статическая или динамическая линковка? :)
Но вот это уж действительно бред, все равно, что спорить что лучше молоток или пассатижи :)
Этот азбучный момент в статье, естественно, не затрагивался, но если кратко то динамическая компоновка должна использоваться всегда когда можно, а статическая только в редких специфических случаях.
то это должен быть размер дистрибутива приложения, а не размер исполняемого файла.
Если вам хочется сравнивать дистрибутивы, то играйтесь на здоровье (в своей реальности :) ), тем более что у вас это так замечательно получается :)
Я предпочитаю в бинаре приложения иметь логику в чистом виде с минимально необходимыми примесями из рантайма.
В вашем примере в Java самый «чистый» бинарь. Такой подход позволяет свободно менять рантайм языка без перекомпиляции приложения.
Неужели Rust-у реально нужно 2305KБ кода чтобы напечатать в консоль строчку? :)
Никаких других внятных причин я в статье не увидел.
Вот в этом и дело, что много пустых споров рождаются на ровном месте, когда «слышат звон, да не знают где он» :)
Nim, Rust:
— жирные бинари (смесь логики и рантайма)
— кросплатформенность
— стабильность рантайма
Rust:
— объектно-ориентирование программирование не поддерживается (да-да, есть альтернативы, я в курсе)
Num:
— нет полноценной поддержки интерфейсов
Это все достаточно серьезные недостатки на мой взгляд (в контексте моих изначальных, в начале статьи, требований к языкам), и по-этому они выбыли из обзора.
Мы обсуждаем не абстрактный код в вакууме, а вполне конкретный тестовый пример.
А… ну ладно тогда, а то вы тут было впали в какую-то блаженную эйфорию, 150 классов и т.д. :)
Есть желание оспорить это утверждение? )))
Глупо спорить, тут надо проверять. Но мне, естественно, лень будет гонять два варианта, поэтому в релиз может войти только версия с полным набором классов.
Этот азбучный момент в статье, естественно, не затрагивался, но если кратко то динамическая компоновка должна использоваться всегда когда можно, а статическая только в редких специфических случаях.
О, очередное шедевральное высказывание в дополнение к статье… Конечно же зачем нам статическая компоновка, если в ней нет ни замедления работы, ни раздувания дистрибутива, и главное в ней нельзя насладится такой очаровательной вещью, характерной для динамической компоновки, как dll hell.
Такой подход позволяет свободно менять рантайм языка без перекомпиляции приложения.
Осталось только уточнить одну «мелочь»: кому и зачем это вообще надо? )))
Это все достаточно серьезные недостатки на мой взгляд (в контексте моих изначальных, в начале статьи, требований к языкам), и по-этому они выбыли из обзора.
Что-то не увидел описания причин выбывания языка D.
Что касается Rust'а, то ему действительно можно предъявить определённые претензии, являющиеся следствием молодости (т.е. процесса активной разработки и не до конца установившимися концепциями) языка. Однако говорить о недостаточной кроссплатформенности Rust довольно смешно, т.к. там в роли бэкенда работает llvm (предлагаю посмотреть на список доступных платформ).
А… ну ладно тогда, а то вы тут было впали в какую-то блаженную эйфорию, 150 классов и т.д. :)150 классов типа perfromer точно так же никак и один такой класса нисколько не изменят производительность данного теста.
Глупо спорить, тут надо проверять. Но мне, естественно, лень будет гонять два варианта, поэтому в релиз может войти только версия с полным набором классов
Ну кому-то возможно и надо проверять, а кому-то достаточно знаний о работе компиляторов C++… )))
О, очередное шедевральное высказывание в дополнение к статье… Конечно же зачем нам статическая компоновка, если в ней нет ни замедления работы, ни раздувания дистрибутива, и главное в ней нельзя насладится такой очаровательной вещью, характерной для динамической компоновки, как dll hell.
Динамическая или статическая компоновка это всего лишь инструмент в арсенале разработчика и им нужно уметь пользоваться.
«dll hell» это следствие неразумного использования динамического связывания и было возможно только в бестолково спроектированных системах. Т.е. это проблема системы, а не самой технологии связывания. Модульность (или пакеты) с зависимостями на определенные версии других модулей/пакетов прекрасно работает.
Я вижу у вас возникает много вопросов на эту тему… В статье речь идет о сравнении ЯП, а не об тонкостях использования того или иного связывания. Это оффтоп, предлагаю вам все-таки воспользоваться гуглом или почитать специальную литературу.
Осталось только уточнить одну «мелочь»: кому и зачем это вообще надо? )))
А если подумать? :)
В первую очередь, конечно же, пользователям приложений.
Зачем им его перестраивать при выходе новой версии Java?
Скомпилированный бинарь будет прекрасно работать на новой версии JVM, а может быть еще и быстрее если разработчики ее оптимизировали. Или вообще на другой JVM и все это без перекомпиляции.
Или зачем пользователем приложения на C++ его перекомпилировать (и потом не все же приложения open source), если создатели C++, например, взяли и поменяли имплементацию unordered_map (исправили баги, оптимизировали).
Что-то не увидел описания причин выбывания языка D.
Да все те же:
— жирные бинари (смесь логики и рантайма)
— кросплатформенность
— стабильность рантайма
Тем не менее в D меня заинтересовала возможность компиляции в LLVM: github.com/ldc-developers/ldc
Но, к сожалению, эта ветка развивается не очень активно, и у меня полезли какие-то странные баги при запуске скомпилированного бинаря, например под Linux на Windows и наоборот. В общем до стабильной работы там похоже должны пройти еще десятилетия.
Однако говорить о недостаточной кроссплатформенности Rust довольно смешно, т.к. там в роли бэкенда работает llvm (предлагаю посмотреть на список доступных платформ).
Мы вроде проходили уже это?
Совсем не важно во что эти языки умеют компилироваться в C/C++ или LLVM. В их случае важнее на сколько платформ портирован их «жирный» рантайм.
Или зачем пользователем приложения на C++ его перекомпилировать (и потом не все же приложения open source), если создатели C++, например, взяли и поменяли имплементацию unordered_map (исправили баги, оптимизировали).
Это как бы шаблон, и он не крутится в рантайме как и вся библиотека stl в принципе. Ну и да реализация stl зависит от производителя компиля и только, создатели С++ никак не могут повлиять на имплементацию, только на интерфейс.
Забавно читать, что вы считаете динамическую линковку лучше статической, для разных задач разные требования. Если бы динамическая линковка была бы всегда лучше то статическая вымерла бы, а получается либо мир программирования неправ либо вы не достаточно компетентны в этом вопросе.
создатели С++ никак не могут повлиять на имплементацию, только на интерфейс.
Ну это не суть кто ее поменяет, не нужно придираться к частностям.
В рантайме есть не только шаблоны и их имплементация вполне может меняться с сохранением бинарной совместимости.
Забавно читать, что вы считаете динамическую линковку лучше статической, для разных задач разные требования.
Я нигде не писал, что динамическая компоновка лучше, это вы меня с другим оратором попутали (случайно или намеренно), только он пишет наоборот:
Я думаю из этих данных вполне очевидно преимущество статической линковки над динамической
Я как раз утверждал, что глупо рассуждать что лучше, повторюсь — статическое и динамическое связывание это инструменты разработчика и ими надо уметь пользоваться.
Т.е. применять по делу, в зависимости от ситуации.
достаточно компетентны в этом вопросе.
Достаточно, если вы не будете передергивать мои ответы в свою пользу.
Ну это не суть кто ее поменяет, не нужно придираться к частностям.
В рантайме есть не только шаблоны и их имплементация вполне может меняться с сохранением бинарной совместимости.
Повторяю в рантайме впринципе не может быть шаблонов stl и как следстви никакой речи о бинарной совместимости и быть не может.
Я нигде не писал, что динамическая компоновка лучше
Не ваши ли слова?
если кратко то динамическая компоновка должна использоваться всегда когда можно, а статическая только в редких специфических случаях.
Дело в том что статическая линковка это не спецефичный случай, если мы рассматриваем С++ то это даже более желательный способ линковки.
Достаточно, если вы не будете передергивать мои ответы в свою пользу.
Возможно, в плане вашего отношения к линковке вас неправильно поняли конечно, но в плане С++ вы точно являетесь не компетентным (шаблоны в рантайме мда)
Повторяю в рантайме впринципе не может быть шаблонов stl и как следстви никакой речи о бинарной совместимости и быть не может.
При чем здесь шаблоны? Вы сами начали о них говорить, «ни к селу ни к городу» :)
Я говорил о рантайме C++ в целом.
Вы утверждаете что он целиком статический?
Если да, то вы сами недостаточно компетентны чтобы судить об этом.
Если нет, то почему, по вашему мнению, динамическая часть не может быть изменена с сохранением бинарной совместимости?
Не ваши ли слова?
Мои. А вы видите разницу между «лучше» и «должна использоваться»?
Дело в том что статическая линковка это не спецефичный случай, если мы рассматриваем С++ то это даже более желательный способ линковки.
Нет. Способ линковки не связан с языком как таковым. Тот же gcc линкует по умолчанию динамически, пока вы не добавите специальный ключ. И делать это нужно в очень редких случаях.
С++ вы точно являетесь не компетентным (шаблоны в рантайме мда)
:))) боюсь что это у вас явные проблемы с компетенцией.
P.S. Давайте уже без этих детских «дурак — сам дурак». Если есть, что написать по делу пишите, а свои субъективные оценки оставьте при себе.
При чем здесь шаблоны? Вы сами начали о них говорить, «ни к селу ни к городу» :)
Эм…
Или зачем пользователем приложения на C++ его перекомпилировать (и потом не все же приложения open source), если создатели C++, например, взяли и поменяли имплементацию unordered_map (исправили баги, оптимизировали
В рантайме есть не только шаблоны
Вы точно уверены что это я начал?
Если нет, то почему, по вашему мнению, динамическая часть не может быть изменена с сохранением бинарной совместимости?
Я говорил исключительно про шаблоны, а это практически весь stl.
Мои. А вы видите разницу между «лучше» и «должна использоваться»?А чем ещё может мотивироваться использование её если это может быть не лучшее решение?
Тот же gcc линкует по умолчанию динамически, пока вы не добавите специальный ключ.Неужели? А я вот всё время думал что тип линковки зависит не от компилятора а от того каким образом была собрана библиотека. А оно вон как оказывается без специального ключа gcc динамическую библиотеку не сможет подключить.
Если есть, что написать по делу пишите, а свои субъективные оценки оставьте при себе.
Ды какие уж субъективные когда вы раз за разом утверждаете про шаблоны в рантайме.
Вы точно уверены что это я начал?
В диалоге с вами я уже ни в чем не уверен :) вы или вправду на «своей волне» и вещаете о чем-то своем или нарочно, пардон, дурака валяете :)
Давайте попробуем синхронизироваться (если у вас конечно нет цели просто пофлудить :) )
Я говорил исключительно про шаблоны, а это практически весь stl.
А зачем вы говорите про шаблоны когда речь совсем о другом? Это вероятно что-то личное? Любите их очень? :)
Я попытался донести до вас (точнее даже не до вас, но вы тоже решили поучаствовать в обсуждении) очень простую мысль (внимание): динамическую часть рантайма (или любой другой динамической библиотеки) всегда можно поменять сохранив при этом бинарную совместимость.
Надеюсь, вы согласны с этим простым посылом?
И шаблоны, которые, кстати, вообще сложно отнести к линковке, т.к. они компилируются прямо из хидеров, здесь совершенно не причем.
А чем ещё может мотивироваться использование её если это может быть не лучшее решение?
Необходимостью в каждом конкретном случае, или как вы сами и написали:
для разных задач разные требования.
Это не «лучше»-«хуже», это когда вам нужно забить гвоздь вы используете молоток, когда закрутить шуруп отвертку.
Неужели? А я вот всё время думал что тип линковки зависит не от компилятора а от того каким образом была собрана библиотека. А оно вон как оказывается без специального ключа gcc динамическую библиотеку не сможет подключить.
Сам призвал не выносить оценок, но… :) ладно будем считать что вы просто забавы ради «включили дурака» :)
Мы ведь с вами за рантайм терли? Так как вы еще его статически влинкуете? По дефолту в gcc он будет в динамике естественно:
-static-libstdc++
gcc.gnu.org/onlinedocs/gcc/Link-Options.html
When the g++ program is used to link a C++ program, it normally automatically links against libstdc++. If libstdc++ is available as a shared library, and the -static option is not used, then this links against the shared version of libstdc++. That is normally fine. However, it is sometimes useful to freeze the version of libstdc++ used by the program without going all the way to a fully static link. The -static-libstdc++ option directs the g++ driver to link libstdc++ statically, without necessarily linking other libraries statically.
Ды какие уж субъективные когда вы раз за разом утверждаете про шаблоны в рантайме.
Вы давайте прекращайте мне всякую отсебятину навешивать :) если вы заблудились в трех соснах не нужно кидаться обвинениями в чужой некомпетентности. Разберитесь сперва о чем вам говорят потом уже судите.
-static-libstdc++А так вы только про рантайм тогда ок, я то думал вы в принципе про любые библиотеки.
динамическую часть рантайма (или любой другой динамической библиотеки) всегда можно поменять сохранив при этом бинарную совместимость.В большинстве случаев да.
Разберитесь сперва о чем вам говорят потом уже судите.
Честно говоря я не знаю как иначе можно интерпретировать эти фразы
Или зачем пользователем приложения на C++ его перекомпилировать (и потом не все же приложения open source), если создатели C++, например, взяли и поменяли имплементацию unordered_map (исправили баги, оптимизировали
В рантайме есть не только шаблоны
может вы их прокомментируете? Или всё также упорно продолжите утверждать что это я начал про шаблоны говорить.
может вы их прокомментируете? Или всё также упорно продолжите утверждать что это я начал про шаблоны говорить.
В моем изначальном посте я говорил от том, что динамический рантайм как в Java так и в C++ может быть изменен с сохранением бинарной совместимости, так?
Это основная мысль.
И вы с ней в итоге согласились:
В большинстве случаев да.
Вы справедливо заметили, что unordered_map это неудачный пример т.к. он построен на шаблонах.
Я с вами согласился и написал:
В рантайме есть не только шаблоны
Т.е. рантайм языка не исчерпывается одними шаблонами, и моя изначальная мысль все равно верна несмотря на неудачный пример.
Но вас же почему-то начало клинить на шаблонах, и дальше разговор потерял всякий смысл.
1) «Рантайм» как библиотека языка обеспечивающая его работу во время выполнения программы. Именно ее я имел ввиду, т.е. саму библиотеку языка в которой есть не только шаблоны. Наверное чтобы не путаться лучше назвать ее стандартной библиотекой С/C++ или просто библиотекой языка.
2) «Рантайм» как скомпилированный код который выполняется. В нем, естественно, шаблонов уже не будет.
Динамическая или статическая компоновка это всего лишь инструмент в арсенале разработчика и им нужно уметь пользоваться.
«dll hell» это следствие неразумного использования динамического связывания и было возможно только в бестолково спроектированных системах. Т.е. это проблема системы, а не самой технологии связывания. Модульность (или пакеты) с зависимостями на определенные версии других модулей/пакетов прекрасно работает.
И что же это интересно за толково созданные системы, в которых нормально работает модульность? Надеюсь речь не про Линух, который не раз дох у меня полностью от банального обновления…
Я вижу у вас возникает много вопросов на эту тему… В статье речь идет о сравнении ЯП, а не об тонкостях использования того или иного связывания. Это оффтоп, предлагаю вам все-таки воспользоваться гуглом или почитать специальную литературу.
В статье на основание не верного представления автора о вопросах компоновки (чего только стоит сравнение размеров исполняемого файла при разных компоновках) делаются вполне однозначные выводы о выборе языков программирования…
В первую очередь, конечно же, пользователям приложений. Зачем им его перестраивать при выходе новой версии Java? Скомпилированный бинарь будет прекрасно работать на новой версии JVM, а может быть еще и быстрее если разработчики ее оптимизировали. Или вообще на другой JVM и все это без перекомпиляции.
Что-то похоже у кого-то в голове путаница между пользователями, админами и разработчиками. Нормальные пользователи не то что не занимаются подобным, они даже не поймут о чём речь.
Или зачем пользователем приложения на C++ его перекомпилировать (и потом не все же приложения open source), если создатели C++, например, взяли и поменяли имплементацию unordered_map (исправили баги, оптимизировали).
Для C++ это вообще не работает, т.к. там большая часть кода (включая unordered_map) является шаблонами.
Да все те же:
— жирные бинари (смесь логики и рантайма)
— кросплатформенность
— стабильность рантайма
Хм, что за глупости? Рантайм там даже меньше чем у C++ выходит. И со стабильностью тоже всё хорошо — язык уже устоялся, в отличие от Rust.
Тем не менее в D меня заинтересовала возможность компиляции в LLVM: github.com/ldc-developers/ldc
Собственно там и gcc есть gdcproject.org )))
Но, к сожалению, эта ветка развивается не очень активно, и у меня полезли какие-то странные баги при запуске скомпилированного бинаря, например под Linux на Windows и наоборот. В общем до стабильной работы там похоже должны пройти еще десятилетия.
Это всё какие-то эксперименты, официальным решением для D является компилятор dmd. И у него со стабильностью всё отлично.
И что же это интересно за толково созданные системы, в которых нормально работает модульность? Надеюсь речь не про Линух, который не раз дох у меня полностью от банального обновления…
Ну вы, наверное, каким-то не кошерными дистрибутивами Linux пользуетесь :)
Попробуйте Debian Stable, там все хорошо.
Да и последние версии Windows весьма стабильны, несмотря на повсеместное использование динамических библиотек.
В статье на основание не верного представления автора о вопросах компоновки (чего только стоит сравнение размеров исполняемого файла при разных компоновках) делаются вполне однозначные выводы о выборе языков программирования…
Начинаем ходит кругами :)
Мои представления о компоновке правильные, а если они у вас другие или просто не достает знаний в этом вопросе это ваши проблемы.
Я уже несколько раз описывал вам причины выбывании части языков из обзора. Вы же все с типом компоновки никак не разберетесь. Давайте может вы уже закончите свои увлекательные эксперименты, а пока оставим эту тему в покое? :)
Для C++ это вообще не работает, т.к. там большая часть кода (включая unordered_map) является шаблонами.
Верно, но в рантайме очень много и другого кода, который не построен на шаблонах.
Хм, что за глупости? Рантайм там даже меньше чем у C++ выходит. И со стабильностью тоже всё хорошо — язык уже устоялся, в отличие от Rust.
Слушайте, ну уже не в первый раз призываю вас воздерживаться от личных выпадов. Для меня тоже 90% из того что вы пишите сплошная глупость, но я ведь об этом не говорю вслух? :)
Иначе наша беседа, у которой и так технический уровень крайне низкий (обсуждаем совершенно базовые вещи — на уровне собеседования со студентом), рискует скатиться в банальную никому не нужную ругань :)
А как вы проверяли стабильность рантайма в D?
Проводилось ли стресс тестирование?
Какие подсистемы языка проверялись?
Или так же умозрительно, руководствуясь, «своими знаниями о работе компилятора»? :)
Может быть рантайм у D и меньше чем у C++, но опять же львиная его часть пихается в бинарь, и динамическая линковка (в отличии от C++) не помогает. Бинари «жирные» — т.е. та же смесь логики программы и рантайма.
Это всё какие-то эксперименты
Эксперименты обязательно нужны даже если вы проводите небольшую исследовательскую работу.
Что-то похоже у кого-то в голове путаница между пользователями, админами и разработчиками. Нормальные пользователи не то что не занимаются подобным, они даже не поймут о чём речь.
Для начала разгребите «завалы» в своей голове, а потом уже выносите суждения о чужой :)
Но если серьезно, обычные пользователи даже не узнают об этом, просто нажмут кнопочку «Обновить Java» и будут продолжать радоваться работе приложения. И это правильно. Но вот разработчик должен четко представлять себе как это все устроено и работает.
Ну вы, наверное, каким-то не кошерными дистрибутивами Linux пользуетесь :) Попробуйте Debian Stable, там все хорошо.
Вот как раз с такими и игрался. Советую попробовать не обновлять подобный дистрибутив 1-2 года и потом запустить обновление…
Да и последние версии Windows весьма стабильны, несмотря на повсеместное использование динамических библиотек.
В Windows как раз не особо употребляется совместное использование динамических библиотек. В системый каталог кладётся только их малое число, а большинство устанавливается в каталог приложения. Так что под Windows у каждого приложения используется своя версия (и на одном компьютере их может быть множество). Хотя и там изредка бывают проблемы из этой области (обычно когда сомнительное ПО прописывает себя в path), но гораздо реже… Только вот это следствие не умной системы зависимостей, а наоборот уход от неё. Точно так же как и на OSX.
Начинаем ходит кругами :)
Мои представления о компоновке правильные, а если они у вас другие или просто не достает знаний в этом вопросе это ваши проблемы.
Я уже несколько раз описывал вам причины выбывании части языков из обзора. Вы же все с типом компоновки никак не разберетесь. Давайте может вы уже закончите свои увлекательные эксперименты, а пока оставим эту тему в покое? :)
Вот что меня действительно поражает, так это ваше полное игнорирование оценок статьи, а так же этой беседы в комментариях — у вменяемого человека хотя бы из-за них возможно закрались бы какие-то сомнения в собственно правоте. Но у вас ни малейших не появилось. Но вы правы в одном: действительно пора заканчивать — мне уже наскучило стучаться в эту стену…
Вот как раз с такими и игрался. Советую попробовать не обновлять подобный дистрибутив 1-2 года и потом запустить обновление…
Ну раз с «такими» значит много каких-то вариантов пробовали и видимо непродолжительное время.
Например, в Ubuntu такое действительно возможно, особенно при переходе на новый релиз каждые пол года, относительно спокойно можно сидеть только на LTS. Ведь Ubuntu основан на ветке Testing репозитория Debian.
Если же вы выбрали в Debian ветку Stable, то уверяю вас, можете совершенно спокойно обновляться хоть через 2 года, хоть через 10.
Просто в Linux софт развивается очень активно, а квалификация авторов различна, и нужны серьезные административные меры чтобы сохранять систему стабильной. Хороший дистрибутив — хорошая стабильность, плохой — такая и стабильность.
А сама по себе система модульности здесь не причем.
В Windows как раз не особо употребляется совместное использование динамических библиотек. В системый каталог кладётся только их малое число,
Ну это как сказать :) загляните в Windows/System32 и в SysWOW64 на 64-х битной системе, думаю несколько тысяч наберется :)
Кстати, забавно, что в 64-х битной версии Windows 64-х битные dll-шки лежат в System32, а 32-х битные в SysWOW64 :)
а большинство устанавливается в каталог приложения. Так что под Windows у каждого приложения используется своя версия (и на одном компьютере их может быть множество).
Я не думаю, что это проявление какой-то сверхмудрости Windows систем, это скорее рудимент, который тянется из древних времен.
Вот что меня действительно поражает, так это ваше полное игнорирование оценок статьи
Так и пробивает вас на психиатрические термины, про вменяемость вон ввинтили теперь :) вы, наверное, все-таки психиатр… лечащий по фотографии :)
Если бы я преследовал цель набрать «плюсики» и пропиариться, я бы, наверное, написал что-нибудь другое, так чтобы наверняка всем понравилось :)
Но я проводил это небольшое исследование для себя, получил ответы на свои вопросы, сделал выводы и просто решил любезно поделиться результатом. Возможно кому-то это будет полезно, возможно нет, для меня это не существенно.
В статье действительно много субъективных оценок, которые можно принимать или нет, но они основаны на моем личном опыте, а не взяты с потолка.
У всех ораторов разный опыт, свое мнение, свое видение, да и голова у всех работает немного по разному, сердиться на это глупо.
В обсуждении я честно пытался разъяснить мотивы тех или иных выводов в статье, если видел что спор затеян не ради спора, а действительно присутствует некоторое недопонимание.
Однако результаты тестов вполне проверяемые цифры и исходники доступны, поэтому дискуссии на эту тему лишены смысла.
Что касается оценок, то если мы говорим о рейтинге сообщений в обсуждении, то тут я с интересом наблюдал «стадный эффект» в полный рост :) Если бы я даже просто написал, что дескать земля вращается вокруг солнца все равно стали бы яростно минусовать :)
Если мы говорим об оценках статьи, то на момент написание этого поста мы имеем 17 положительных оценок и 41 отрицательную, итог -24. Общее число просмотров статьи 6,3k (конечно нельзя утверждать, что ее просмотрело именно такое количество людей и тем не менее), получается процент серьезно недовольных около 0.38%, меньше процента :)))
А в Java смотреть какие jar-ы подгрузились.
Только зачем? :)
Это дальше уже некоторые энтузиасты увлеклись бессмысленными сравнениями каких-то дистрибутивов.
Потом вдруг сделали из своих же сравнений странный вывод «о преимуществе статической линковки на динамической» :)
Еще один товарищ уже шаблоны к этой теме примеряет, градус абсурда все крепчает :)
Каких еще откровений ждать? :)
Мне уж самому стало интересно до чего еще додумаются? :)
Подскажите, а как Вы запускали приложения? Я тут ради интереса произвел запуск приложения на Scala тремя способами:
- из консоли sbt командой run
- scala — jar файл для scala (scala test.jar)
- Java — jar файл включающий библиотеки скалы, который может выполнятся только с java (java -jar test.jar)
И получил три разных варианта. Самый быстрый — из консоли sbt. Первый примерно тоже самое, что и Qt, а со второго запуска, отработал почти вдовое быстрее. Два других работали в двое медленнее, чем на Qt. Причем это только показатель замеров программы, реально было еще дольше.
Больше чем Java?