Вот было время... Если нужно чтобы что-то оптимально по производительности работало - брали фортран, в котором нет сионистских проблем. А сейчас чуть что - расчихляют кресты...
Есть простая функция:
void squareArrayWith100500Items (int* const dest, const int* const source) { for ( int i=0; i < 100500; ++i) { dest[i] = source[i]*source[i]; } }
Казалось бы всё хорошо, но нет. C++\C, в отличии от нормальных языков, для данной функции не может провести часть оптимизаций и предрасчётов во время компиляции, не может векторизовать этот цикл, не может распараллелить его.
А всё почему?
А потому что не уверен перекрываются ли указатели dest и source. Поэтому ему приходится считать все элементы попорядку, а не параллельно, а также убирать часть препросчётов и прочих оптимизаций.
Указатели вредят совремнной автоматической оптимизации C++. Теги для поиска: [ КРЕСТОПРОБЛЕМЫ C++ кококомпиляция ]
Одно из возможных решений проблемы:
В C99 ввели ключевое слово restrict, дабы указывать, что указатели не перекрываются и пользоваться автоматической оптимизацией.
На двух крестах создатели и стандартизаторы давно поставили крест и не ввели этот keyword. Мертвому припарки не нужны.
Понятно, что некоторые крестокомпиляторы содержат различные вендор специфик расширения, типа __restrict, restrict__ и прочей
ерунды. Вообщем детский сад там -->
Что же нам предлагают крестосоздатели, для решения данной проблемы?
А вот что:
int a[100500];
, а не так:
int* a=new int[100500];
Ну нет в языке понятия динамического массива, который бы более или менее гарантировал отсутвия перекрытий. Они эмулируются через указатели, которые не может нормально оптимизировать компилятор. Чистоты тоже нет...
Ещё они предлагают писать везде во всех функция, что видит глаз и пишет рука вот так:
template<const int ItemCount> void squareArray (int ( &dest)[ItemCount], int ( &source)[ItemCount]) { for ( int i=0; i < ItemCount; ++i) { dest[i] = source[i]*source[i]; } }
Это как раз нужно для имитации тех самых int a[100500] массивов с фиксированным размером, без которых С++ не справляется. Определенно они хотят, чтобы мы больше писали лишних строк кода, запихивали все функции в хедеры, тк они все шаблонные, и ждали долгими ночами окончания затяжной крестоboooooooringкомпиляци из-за этих самых шаблонов в хедерах.
Понятно, что
void squareArrayWith100500Items (vector<int> dest, vector<int> source)
нас никак не спасёт, тк там внутри все тотже int* и определить отсутсвие перекрытий компилятор не может.
И так взгляним на прочие убогие тормозные не оптимизирующиеся конструкции:
for(int* a=p; e!=a; ++a)//...
Пока p или e указатель - оптимизатор С++ почти ничего не может поделать.
for(vector::iterator a=container.begin( ); container.end( )!=a; ++a)//...
Абсолютно теже проблемы. Итераторы только ухудшают ситуацию, а ведь всё STL в С++ построено на итераторах. Никаких шансов распараллелить.
for(auto item : container)//...
Теже проблемы итератора, тк внутри по прежнему используются итераторы.
std::copy//...
Ну и опять все на итераторах всё будет медленно и печально выполнятся, если нет хоть какихто параллельных специализаций (а их нет обычно). Разведение всех этих оптимальных специализаций шаблонов под ситуацию - перекладывание автоматической работы с компилятора на программиста.
Вообщем массивы фиксированного размера и индексный доступ к ним спасут отца русской демократии.
И вообще STL спроектирован очень неоптимально и опасно.
Теже проблемы указателя:
OutputIterator copy (InputIterator first, InputIterator last, OutputIterator destinationBegin )
Вот нет чтобы добавить перегрузку функции и дать мне написать destinationEnd, чтобы не было переполнения, а они заставляют вручную следить за тем, чтобы в destination всё вместилось и не переполнилось. Вручную выделить память под него. Есть всякие back_inserter, но не всегда это можно применить да и темболее не так оптимально.
Видимо они мне предлагают взять и померить количество элементов между first и last, например size_t NeedDestinationSize=std::distance(first, last); А потом выделить память нужной длины (NeedDestinationSize) для destination.
И конечно же вся stl совершенно не продумана и приносит производительность в жертву обобщённости. Вплоть до того, что std::distance (функция, определяющая кол-во элементов) имеет сложность до О(n). ко ко ко!
И таких мест куча. И вообще писать на нем долго и неудобно, словно нам платят за строчки кода. Сделали бы и такую перегрузку для stl алгоритмов:
Output std::algorithm1 (Input first, Output destination ) /*, а то ведь каждый раз приходится писать:*/ std::algorithm1 ( source.begin( ), source.end( ), destination.begin( ), destination.end( ) )
Вообщем куча неэфективности (по производительности приложений и по производительности программистов и по надёжности) на пустом месте. Теги для поиска: [ КРЕСТОПРОБЛЕМЫ C++ кококомпиляция ]
Тут на тестах интерпретируемый OCaml обогнал С\С++ по озвученной выше причине, а компилируемый темболее, а С++ почти догнал питон.
TROLOLO mode cannot be disabled.
laMer007
> Тут на тестах интерпретируемый OCaml обогнал С\С++ по озвученной выше причине
...
I wrote the LCS algorithm in a bunch of different languages, to compare how complex the code was, and how fast it ran. I wrote the comp bio algorithm in C, C++, OCaml, Java, and Python, and recorded the results. What I got timing-wise for running the programs on arrays of 2000 elements each was:
C: 0.8 seconds.
C++: 2.3 seconds.
...
C: 0.8 seconds.
C++: 2.3 seconds.
C: 0.8 seconds.
C++: 2.3 seconds.
А мужичок то, походу большой знаток C++ в кавычках. =)))
=A=L=X=
> А мужичок то, походу большой знаток C++ в кавычках. =)))
Или очередной trololo.
laMer007
> Ещё они предлагают писать везде во всех функция, что видит глаз и пишет рука
> вот так:
>
> template<typename ItemCount>
> void squareArrayWith100500Items (int (&dest)[ItemCount], int
> (&source)[ItemCount])
> {
> for (int i=0; i < 100500) {
> dest[i] = source[i]*source[i];
> }
> }
> }
а хотелось бы писать вот так:
dest = [x*x || x<-source]
и вот после этого ФП оно конечно плохое, а вот плюсы они конечно хорошие, ога.
ЗЫ: верблюд всё равно не труЪ, как бы его не хвалили.
Кстати, я сейчас пописываю на досуге одну программульку и вы не поверите, стыдно до слез. В ней присутствует дерево node/childs. Так вот в Node я храню std::vector<Node> childs. И вы не поверите - при построении дерева передаю ноды ПО ЗНАЧЕНИЮ. Т.е. в начале всего рекурсия выглядит так:
Node root = buildRootNode( ... ); // <- плачь, детка, плачь, мне большего не надо
и внутри в таком же духе.
ffinder
> ЗЫ: верблюд всё равно не труЪ, как бы его не хвалили.
Полностью императивный код писать позволяет, писать нужно меньше, чем в С++, что ещё нужно императивщику?
JohnSmith
Вы только посмотрите, мы идём в век многоядерых систем, в массовый параллелизм, автораспараллеливание, компиляторы и языки умнеют на глазах, построено много моделей многопоточности (более удобных и надёжных, чем старые).
А вы посмотрите что нам дают в новом стандарте C++11? А ничего нового. Они наконец удосужились добавить в стандарт языка модель многопоточности 40летней давности. Да это все равно, что добавить в высокоуровневый язык поддержку дополнительного языка типа ассемблер для регулярного использования на всех многоядерных платформах.
Добавить новые модели многопоточности они просто не в состоянии, тк легаси костыли С++ и не правильное проектирование этого языка просто не дадут это сделать.
Они даже древний примитив междупотоковой синхронизации ReaderWriterLocker умудрились не добавить, хотя в boost он был.
STL, как и сам язык вообще никаким боком не лежит к автораспараллеливанию и к лёгкому ручному распараллеливанию тоже. Все конструкции языка опасные (бег по лезвию бритвы), громоздкие и<угловатые>. Автоматического вывода типов почти нет (куча писанины из-за этого), нормальной стандартной библиотеки тоже нет.
Этот язык просто не пригоден к применению новых высокоуровневых моделей многопоточной среды. Поэтому все эти С++11 - все равно, что мертвому припарка. ко ко Комитет стандартизации, пытаясь продлить жизнь трупу, занимается некроманстовом и некрофилией.
&8>
Да, тут нужна революция. Хватит это терпеть! Уничтожайте все исходные коды С++ программ! Как только все исходники канут в омут - мейнстрим ни на секунду не задумается перед уничтожением говёных тормозных компиляторов С++.
Эти компиляторы были нужны только для поддержки устаревшего легаси кода миллионов библиотек С++. Как только этот код падёт - компиляторы С++ на всегда останутся в аналах истории, как самая бесполезная трата сил и средств мирового сообщества.
laMer007
> Да, тут нужна революция. Хватит это терпеть! Уничтожайте все исходные коды С++
> программ! Как только все исходники канут в омут - мейнстрим ни на секунду не
> задумается перед уничтожением говёных тормозных компиляторов С++.
Теперь понятно, зачем ты искал исходники boost.
laMer007
> > ЗЫ: верблюд всё равно не труЪ, как бы его не хвалили.
> Полностью императивный код писать позволяет, писать нужно меньше, чем в С++,
> что ещё нужно императивщику?
сам же понимаешь, что от императивного кода нужно избавлятся.
профиту от верблюда все равно нет в таком случае.
Ах, кресты, вы мои кресты, судеб сломанных пол версты
laMer007
Пролог не спасёт отца русской демократии ? :)
Так что разом все переходим на С или рано еще?
JohnSmith
Погоди, не гони, таксист
Чтоб схватил батхёртца дельфист
Ну, первое обходится при помощи OpenMP...
Только ты не узнаешь, слез моих не увидишь,
Не срастется вовеки сломанная куча,
Исключенье кидая, никогда не раскайся,
Я кидаю на плюсы, сборщик муууусора лучшеее!!!
Я иду по улице, словно чумачечий,
Выучил вчера я лисп, потерял дар речи,
В стёклах отражаются лямбды и кложуры,
Струструп и Керниган выглядят как дуры.
Пришла и оторвала голову нам чумачечая эФйЯ
И нам не до сна,
И потихоньку схожу я с ума,
чумачечая эФйЯ,чумачечая.
Чумачечая эФйЯ пришла и крышу нам с тобой снесла,
Чумачечая эФйЯ пришла-ла-ла-ла-ла-ла-ла-ла-ла-ла-ла.
Тема в архиве.