Да, хорошо написанный C ++ значительно быстрее. Если вы пишете программы, критичные к производительности, и ваш C ++ не так быстр, как C (или в пределах нескольких процентов), то что-то не так. Если ваша реализация ObjC работает так же быстро, как C, то что-то обычно неправильно - то есть программа, вероятно, плохой пример ObjC OOD, потому что она, вероятно, использует некоторые «грязные» трюки, чтобы подняться ниже уровня абстракции. работающих внутри, таких как прямой доступ к ивару.
Сравнение Майка Эша очень вводит в заблуждение - я никогда не рекомендовал бы подход для сравнения времени выполнения написанных вами программ или рекомендовал бы сравнивать C с C ++ и ObjC. Представленные результаты получены из теста с оптимизацией компилятора отключен . Программа, скомпилированная с отключенными оптимизациями, редко используется при измерении времени выполнения. Рассматривать его как эталон, сравнивающий C ++ с Objective-C, некорректно. В тесте также сравниваются отдельные функции, а не целые, оптимизированные для реального мира реализации - отдельные функции в обоих языках комбинируются по-разному. Это далеко от реалистичного эталона производительности для оптимизированных реализаций. Примеры: При оптимизации , включенной , кэш IMP
работает так же медленно, как и вызовы виртуальных функций. Статическая диспетчеризация (в отличие от динамической диспетчеризации, например, с использованием virtual
) и вызовы известных типов C ++ (где динамическая диспетчеризация может быть обойдена) могут быть агрессивно оптимизированы. Этот процесс называется девиртуализацией, и при его использовании функция-член, которая объявляется virtual
, может даже быть inline
d. В случае теста Майка Эша, когда много вызовов выполняются для функций-членов, которые были объявлены virtual
и имеют пустые тела: эти вызовы оптимизируются на полностью , когда тип известен, потому что компилятор видит реализация и в состоянии определить динамическую диспетчеризацию не требуется. Компилятор также может исключать вызовы malloc
в оптимизированных сборках (в пользу стекового хранилища). Таким образом, включение оптимизации компилятора в любом из C, C ++ или Objective-C может привести к значительным различиям во времени выполнения.
Это не значит, что представленные результаты совершенно бесполезны. Вы можете получить некоторую полезную информацию о внешних API, если вы хотите определить, существуют ли измеримые различия между временем, которое они проводят в pthread_create
или +[NSObject alloc]
на одной платформе или архитектуре по сравнению с другой. Конечно, эти два примера будут использовать оптимизированные реализации в вашем тесте (если только вы не разрабатываете их). Но для сравнения одного языка с другим в программах, которые вы компилируете ... представленные результаты бесполезны с отключенной оптимизацией.
Создание объекта
Рассмотрим также создание объектов в ObjC - каждый объект размещается динамически (например, в куче). В C ++ объекты могут создаваться в стеке (например, примерно так же быстро, как создание структуры C и во многих случаях вызывать простую функцию), в куче или в качестве элементов абстрактных типов данных. Каждый раз, когда вы выделяете и освобождаете (например, через malloc / free), вы можете ввести блокировку. Когда вы создаете структуру C или C ++ в стеке, блокировка не требуется (хотя внутренние элементы могут использовать выделения кучи), и она часто стоит всего несколько инструкций или несколько инструкций плюс вызов функции.
Кроме того, объекты ObjC являются экземплярами с подсчетом ссылок. Фактическая потребность в объекте, который должен быть std::shared_ptr
в критичном к производительности C ++, встречается очень редко. В C ++ нет необходимости или нежелательности делать каждый экземпляр общим экземпляром с подсчетом ссылок. У вас гораздо больше контроля над владением и временем жизни с C ++.
Массивы и коллекции
Массивы и многие коллекции в C и C ++ также используют строго типизированные контейнеры и непрерывную память. Поскольку адрес членов следующего элемента часто известен, оптимизатор может сделать гораздо больше, и у вас есть отличная локальность кеша и памяти. С ObjC это далеко от реальности для стандартных объектов (например, NSObject
).
Отправка товара
Что касается методов, многие реализации C ++ используют мало виртуальных / динамических вызовов, особенно в высокооптимизированных программах. Это статические вызовы методов и корм для оптимизаторов.
В методах ObjC каждый вызов метода (отправка сообщения objc) является динамическим и, следовательно, является брандмауэром для оптимизатора. В конечном итоге это приводит ко многим ограничениям или неудобствам в отношении того, что вы можете и не можете делать, чтобы поддерживать производительность на минимуме при написании критически важного для производительности ObjC. Это может привести к более крупным методам, кешированию IMP, частому использованию C.
Некоторые приложения реального времени не могут использовать любые сообщения ObjC в своих путях рендеринга. None - аудио рендеринг является хорошим примером этого. ObjC рассылка просто не предназначена для целей реального времени; Распределение и блокировки могут происходить за кулисами при обмене сообщениями объектов, что делает сложность / время обмена сообщениями objc настолько непредсказуемым, что при воспроизведении аудио может быть превышен его срок.
Другие особенности
C ++ также предоставляет реализации обобщений / шаблонов для многих своих библиотек. Они очень хорошо оптимизируют. Они безопасны для типов, и много шаблонов и оптимизаций могут быть сделаны с помощью шаблонов (считайте, что это полиморфизм, оптимизация и специализация, которая имеет место при компиляции). C ++ добавляет несколько функций, которые просто не доступны или не сравнимы в строгом ObjC. Попытки напрямую сравнивать языки, объекты и библиотеки, которые сильно отличаются друг от друга, не так полезны - это очень небольшое подмножество реальных реализаций. Лучше расширить вопрос до библиотеки / фреймворка или реальной программы, учитывая многие аспекты проектирования и реализации.
Другие очки
Символы C и C ++ могут быть легко удалены и оптимизированы на различных этапах сборки (разбор, удаление мертвого кода, встраивание и раннее встраивание, а также оптимизация времени соединения). Преимущества этого включают уменьшение размера двоичных файлов, сокращение времени запуска / загрузки, снижение потребления памяти и т. Д. Для одного приложения это может быть не таким уж большим делом; но если вы повторно используете много кода, и вы должны это сделать, то ваши совместно используемые библиотеки могут добавить много ненужного веса программе, если реализован ObjC - если вы не готовы перепрыгнуть через некоторые пламенные обручи. Поэтому масштабируемость и повторное использование также являются факторами в средних / крупных проектах и в группах, где повторное использование является высоким.
Включенные библиотеки
Разработчики библиотеки ObjC также оптимизируют среду, поэтому разработчики библиотеки могут использовать некоторые функции языка и среды, чтобы предлагать оптимизированные реализации. Хотя при написании оптимизированной программы в чистом ObjC существуют некоторые довольно существенные ограничения, в Какао существуют некоторые высокооптимизированные реализации. Это одна из сильных сторон Cocoa, хотя стандартная библиотека C ++ (то, что некоторые люди называют STL) тоже не лишена. Какао работает на гораздо более высоком уровне абстракции, чем C ++ - если вы плохо знаете, что делаете (или должны делать), работа ближе к металлу может стоить вам . Обратиться к хорошей реализации библиотеки, если вы не являетесь экспертом в какой-либо области, это хорошая вещь, если вы действительно не готовы учиться. Кроме того, среда какао ограничена; Вы можете найти реализации / оптимизации, которые лучше используют ОС.
Если вы пишете оптимизированные программы и имеете опыт работы в C ++ и ObjC, реализации clean C ++ часто будут в два раза быстрее или быстрее, чем clean ObjC (да, Вы можете сравнить с какао). Если вы знаете, как оптимизировать, вы часто можете делать абстракции общего назначения более высокого уровня. Хотя некоторые оптимизированные реализации C ++ будут такими же быстрыми или медленными, как у Cocoa (например, моя первоначальная попытка ввода-вывода файлов была медленнее, чем у Cocoa - главным образом потому, что реализация C ++ инициализирует свою память).
Многое зависит от языковых особенностей, с которыми вы знакомы. Я использую оба языка, они имеют разные сильные стороны и модели / модели. Они хорошо дополняют друг друга, и для них есть отличные библиотеки. Если вы реализуете сложную, критичную по производительности программу, правильное использование функций и библиотек C ++ даст вам гораздо больший контроль и значительные преимущества для оптимизации, так что в правильных руках «в несколько раз быстрее» является хорошим ожиданием по умолчанию ( не ожидайте победы каждый раз или без какой-либо работы, однако). Помните, что для понимания C ++ достаточно хорошо, чтобы действительно достичь этого уровня.
Большинство моих критических для производительности путей я сохраняю как C ++, но также признаю, что ObjC также является очень хорошим решением для некоторых проблем и что есть несколько очень хороших доступных библиотек.