Здравствуйте, lpd, Вы писали:
lpd>Незнаком с деталями последних раработок Java и C#, однако все еще он исполняется в 2-4 раза медленне, чем процессорные коды.
Эммм, а можешь рассказать свое понимание, что же конкретно исполняется в Java и C# и как оно по твоему вообще работает?
Re[20]: Visual C# vs C++. Надо сравнить перспективы.
_>struct Test{
_> string data;
_> Test(const string& s): data(s) {cout<<this_thread::get_id()<<" constructor: "<<data<<endl;}
_> Test(const Test& t) {data=t.data; cout<<this_thread::get_id()<<" copy constructor: "<<data<<endl;}
_> Test(Test&& t) {data=move(t.data); cout<<this_thread::get_id()<<" move constructor: "<<data<<endl;}
_> ~Test() {cout<<this_thread::get_id()<<" destructor: "<<data<<endl;}
_> void print() {cout<<this_thread::get_id()<<" print: "<<data<<endl;}
_>};
_>int main()
_>{
_> thread second, third;
_> second=thread([&]{
_> Test test("hello world");
_> test.print();
_> third=thread([&](Test&& t){
_> second.join();//ждём завершения родительского потока, чтобы всё было по честному (было ясно, что данные берутся не из его стека)
_> t.print();
_> }, move(test));
_> });
_> second.join();
_> third.join();
_>}
_>
_>Выдаёт такой результат: _>
_>2 constructor: hello world
_>2 print: hello world
_>2 move constructor: hello world
_>2 move constructor: hello world
_>2 destructor:
_>2 destructor:
_>3 print: hello world
_>3 destructor: hello world
_>
Скомпилировал clang++ в linux и запустил этот код и получил undefined behaviour:
140353170302720 constructor: hello world
140353170302720 print: hello world
140353170302720 move constructor: hello world
140353170302720 move constructor: hello world
140353170302720 destructor:
140353170302720 destructor:
terminate called after throwing an instance of 'std::system_error'
what(): Invalid argument
Aborted (core dumped)
У сложных вещей обычно есть и хорошие, и плохие аспекты.
Берегите Родину, мать вашу. (ДДТ)
Здравствуйте, Qbit86, Вы писали:
_>>Но ты вместо этого продолжаешь оправдываться, да ещё и пытаешься какие-то переходы на личности делать... Q>Напомню, что вся ветка началась с твоего перехода на мою личность.
Нет, я всего лишь уточнил, что написанная тобой фраза — это бред (как собственно и было). Про тебя лично я ничего не писал.
Q>>«Потому что компилятор на «этапе чтения мной кода» (евпочя) не имеет достаточной информации» _>>Соответственно или ты тут нечаянно обозвал анализатор кода IDE компилятором Q> Да нет, вполне осознанно; не предвидя, конечно, что это у кого-то вызовет недоумение.
О, у нас появилась новая теория... ) Ну послушаем... )))
_>>Каких-либо ещё вариантов интерпретации этой твоей цитаты быть не может. Q>Объясняю, как работает компиляция. Исходный код подвергается лексическому и синтаксическому анализу, строится некая его модель, даже несколько по желанию, например: AST, конкретное синтаксическое дерево, семантическое дерево, таблица символов, etc. Это условный фронт-энд. Дальше модель подвергается всяким преобразованиям, меняет ряд представлений, проходит через какие-то оптимизации, SSA-формы и тому подобное; например, втискивается в модель LLVM, etc.
Q>Так вот, для полноценного анализа кода нужно фактически пропустить исходник через фронт-энд. Это не обязательно тот же фронт-энд, что в фактическом «компиляторе». Но его создание — описание грамматики (подмножества) языка, реализация парсинга в соответствии с этой грамматикой, организация символов, контекстно-зависимое разрешение еоднозначностей — это существенная часть компилятора. Люди, которые этим занимаются называют себя компиляторщиками — даже если они подсвечивают IDE, а не генерируют исполняемый код. Очевидно желание столь значительную часть переиспользовать, поэтму Майкрософт перешёл от C#-компилятора, написанного на C++, к компилятору, который использует общую платформу Roslyn, и шарит её с командой, разрабатывающей IDE. Чтоб не приходилось поддерживать ещё один параллельный независимый компилятор для целей IDE.
Забавненько. ) Теперь тебе осталось только приложить какие-нибудь ссылочки, где мы увидим как авторы навигации по C++ коду в IDE называют себя "компиляторщиками" и тогда можно будет посчитать что это твоё объяснение является истиной, а не попыткой смешной отмазки с помощью буйной фантазии. )))
_>>Вот сразу видно хорошо аргументированное утверждение. Q>Вместо тысячи слов — одна картинка э... из тысячи слов. Q>Image: 2551532
"Сильная" аргументация продолжается... )))
_>>Вообще то я не советовал ему именно C++. Перечитай моё сообщение повнимательнее. Q>Ты так написал, что C++ чуть ли не вариант по-умолчанию, так как «универсальность». Вместо того, чтоб написать, что это last resort — если нет никакой возможности избежать, только тогда берите C++.
Нет, я писал ему что всё зависит от такого, какая команда у него есть в наличие/может быть нанята. )
_>>(всё же макросы заметно проще шаблонов). Навигация в таких случаях работает корректно в любом случае, т.к. она контекстная. Подсветка (неактивная ветка ifdef обычно подсвечивается серым фоном) Q>Откуда контексту взяться? Я читаю исходный файл библиотеки, внутри него перехожу к определению функции, навигация переводит меня в «не серую» ветку. Но в дальнейшем, когда я буду вызывать это в своём коде — кто знает, после каких дефайнов заинклудится мне файл библиотеки? Даже в разных единицах трансляции по разному может быть.
Я имел в виду, когда переходишь из использующих этот файл исходников (в которых находятся указанные макросы). А если ты бродишь только по этому файлу, то как я уже говорил, активная область будет определяться настройками проекта. )
Re[21]: Visual C# vs C++. Надо сравнить перспективы.
Здравствуйте, lpd, Вы писали:
lpd>Скомпилировал clang++ в linux и запустил этот код и получил undefined behaviour: lpd>
lpd>140353170302720 constructor: hello world
lpd>140353170302720 print: hello world
lpd>140353170302720 move constructor: hello world
lpd>140353170302720 move constructor: hello world
lpd>140353170302720 destructor:
lpd>140353170302720 destructor:
lpd>terminate called after throwing an instance of 'std::system_error'
lpd> what(): Invalid argument
lpd>Aborted (core dumped)
А, у тебя линух, понятно. Ну замени там первый second.join(); на какой-нибудь банальный this_thread::sleep_for(1s); и всё заработает. Это не имеет отношения к обсуждаемому нами вопросу, а связано с ожиданием завершения потока из двух других в pthread. В общем это тема отдельной дискуссии на тему синхронизации, можем тоже обсудить, если захочешь, но к вопросу передачи "локального" объекта между потоками это никакого отношения не имеет. )
Re[21]: Visual C# vs C++. Надо сравнить перспективы.
Здравствуйте, lpd, Вы писали:
lpd>Скомпилировал clang++ в linux и запустил этот код и получил undefined behaviour:
lpd>На мой взгляд — обычный C++ это баланс производительностью, удобством и простотой, с возможностью ручного ассемблера.
Ага, еще С++ кроссплатформенный!
Здравствуйте, vdimas, Вы писали:
V>Продолжаем откровенно притормаживать.
Хамовато.
V>1. Было написано (специально): V>
для ref-типов
Я это прочитал, но не увидел смысла игнорировать value-типы — они нужны.
V>А у тебя в примерах идёт вызов метода именно у типа Т. :facepalm:
Обычное дело, в этом нет ничего криминального. Чему тут дивиться, как баран на новые ворота? В C++ такое сплошь и рядом, вызываются методы или запрашиваются typedef-алиасы у параметров шаблона. К чему твой «:facepalm:»? Ты точно ел ту собаку?
V>2. Большинство алгоритмов даже из базовой библиотеки не работают на value-типах, кроме случаев, когда этот тип является элементом контейнера (или последовательности), т.е. кроме тех случаев, когда НИКАКИХ методов у целевого типа T не вызывается.
internal class GenericEqualityComparer<T>: EqualityComparer<T> where T: IEquatable<T>
Так вот, он не только работает на value-типах; он фактически ради них-то и сделан — для value-типов особенно важно реализовать `IEquatable<T>`, чтобы избежать случайного боксинга, а в каких-то случаях ещё и рефлекшна. Похоже, «ты накосячил в рассуждених».
V>Собсно, вообще таких алгоритмов мало, которые можно выразить в дотнете для value и ref-типов в генериках и они будут корректно работать в обоих случаях. Я одно время на этом собаку съел, в поисках классов таких алгоритмов, которые, таки, работают в обоих случаях и в попытках сформулировать ограничения на такие алгоритмы.
И почему бы им корректно не работать на value-типах? Ты какую-то не ту собаку съел. Value-типы нужны, чтобы избежать ненужных алокаций (но имеют свои ограничения), зачем от них отказываться, нужно наоборот поощрать их аккуратное использование. «Ты, вообще, программист или где? Сосредоточься, или не пиши.»
V>А у тебя какой-то детсад прёт, сорри: "а вот бывает... а вот если...".
Не «вот бывает», а прямо сейчас подобный обобщённый код пишу. «:facepalm:»
V>ты можешь ввести тот самый исскуствепнный "общий" интерфейс и выразить ограничения через него.
«:facepalm:» Пусть есть независимые констрейнты (пачки сигнатур методов) `IBarable1`, `IBarable2`, `IBarable3`, etc. Мы хотим написать несколько алгоритмов `Foo1(...)`, `Foo2(...)`, etc. Первому нужны методы из `IBarable2` и `IBarable3`, но не требуются из `IBarable1`. Второму нужны `IBarable1` и `IBarable3`, третьему — `IBarable1` и `IBarable2`, и так далее. Как строить иерархию и, главное, зачем?
V>И абсолютно ничего ни в одном месте, где будет или использована такая структура (или уже была исопльзована), не поломается и не изменится. Ни-че-го.
«И опять рука-лицо.» В общем случае ввести подобный тип возможности может и не быть. Констрейнты могут выражаться уже существующими интерфейсами из какой-то сторонней, или даже стандартной библиотеки. Пользовательский класс их реализует; или даже какой-то 3rd-party-класс, используемый пользователем. Я хочу написать алгоритм, который можно выразить в терминах этих констрейнтов. Если я введу свой новый интерфейс, я сделаю непригодным алгоритм к использованию с существующим классом, который реализует достаточные и необходимые методы, но не реализует искуственно склеенного интерфейса.
V>Предлагаю завязывать, бо мне уже трудно сдерживать откровенное глумление...
Ты пишешь слишком много каких-то глупостей ради ситуативных увёрток, о каком ещё глумлении с твоей стороны может идти речь :) Но твоё решение завязать одобряю.
Здравствуйте, alex_public, Вы писали:
_>Нет, я всего лишь уточнил, что написанная тобой фраза — это бред (как собственно и было). Про тебя лично я ничего не писал.
_>Теперь тебе осталось только приложить какие-нибудь ссылочки
И зачем мне это делать? Я не твой личный Гугл. Я вроде доступно объяснил, что я имел в виду, и почему нет ничего криминального в утверждении, что в навигации, рефакторингах и подсветках ошибок в IDE пользователю помогает компилятор. (Ну или не помогает в случае C++.) У меня ж нет цели убеждать лично тебя :) За топикстартера страшновато, особенно после перенесения ветки во /flame, где, очевидно, плюсовое лобби сильно как нигде.
_>О, у нас появилась новая теория... ) Ну послушаем... )))
Давай лучше расскажи за `this_thread::sleep_for(1s);` из соседнего трэда (pun intended). Может, лучше сразу `sleep_for(2s);`, чтоб наверочку?
И, раз уж массив указателей это плохо для кэша, то почему это не плохо для массива moveable-объектов, которые (для реализации move-семантики) реализованы через тот же указатель, только внутри?
Здравствуйте, alex_public, Вы писали:
_>Вообще то move-семантика — это как раз реальная киллер-фича, которая принципиально увеличивает эффективность кода. Причём каких-то даже близких аналогов этой фичи нет ни в одном из мейнстрим языков.
When we transfer ownership to something else, we say that we’ve ‘moved’ the thing we refer to. You don’t need some sort of special annotation here, it’s the default thing that Rust does.
Там наоборот в отличие от C++: по умолчанию перемещение; а если необходима копия, то нужно реализовывать трейт Copy.
Здравствуйте, Qbit86, Вы писали:
Q>И, раз уж массив указателей это плохо для кэша, то почему это не плохо для массива moveable-объектов, которые (для реализации move-семантики) реализованы через тот же указатель, только внутри?
Там тоже индерекции, и это тоже плохо.
Но фишка в том что семантика перемещения помогает снизить количество индерекций. Для примера vector<vector<something>> вместо лишней индерекции на vector<some_ptr<vector<something>>>.
Плюс value-семантика сама по себе часто удобнее чем reference-semantic.
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Там тоже индерекции, и это тоже плохо. EP>Но фишка в том что семантика перемещения помогает
Я в курсе, какие преимущества даёт семантика перемещений. (Но за ответ всё равно спасибо, потому что ведь ветку могут читать плюсовые программисты, которые ещё не в курсе.) Я не всерьёз спросил, просто чуть дровишек подкинуть. Чтоб у неискушённых адептов C++ не возникло превратного впечатления после разговора с евангелистами. А то ведь как, одни говорят: стековые переменные, кэш-попадания, нет аллокаций/индирекций, нет указателей. Другие говорят: Pimpl для сокрытия реализации за указателем, безопасность исключений по Абра(ха)мсу, swap/move через указатели, etc. Диалектика.
Здравствуйте, Qbit86, Вы писали:
Q>Чтоб у неискушённых адептов C++ не возникло превратного впечатления после разговора с евангелистами. А то ведь как, одни говорят: стековые переменные, кэш-попадания,
Конечно.
Q>нет аллокаций/индирекций,
Есть, но намного меньше.
Q>нет указателей.
Есть, но намного меньше.
Q>Другие говорят: Pimpl для сокрытия реализации за указателем,
Pimpl обычно применяется только на границе API/ABI, а не по всему коду.
Q>swap/move через указатели
Опять-таки, наличие move помогает уменьшить колличесвто указателей, индерекций и аллокаций — ты здесь видишь какое-то противоречие?
Re[22]: Visual C# vs C++. Надо сравнить перспективы.
Здравствуйте, alex_public, Вы писали:
_>А, у тебя линух, понятно. Ну замени там первый second.join(); на какой-нибудь банальный this_thread::sleep_for(1s); и всё заработает.
Или не заработает, если нагрузка в момент запуска будет высокой.
_> Это не имеет отношения к обсуждаемому нами вопросу, а связано с ожиданием завершения потока из двух других в pthread. В общем это тема отдельной дискуссии на тему синхронизации, можем тоже обсудить, если захочешь, но к вопросу передачи "локального" объекта между потоками это никакого отношения не имеет. )
Имеет-имеет. Охренительная просто кроссплатформенность, банальный join не работает. Причём, я уверен что если вызвать какой-нибудь аналог WaitForSingleObject(threadHandle) из libc, то всё работать будет.
Здравствуйте, Qbit86, Вы писали:
_>>Нет, я всего лишь уточнил, что написанная тобой фраза — это бред (как собственно и было). Про тебя лично я ничего не писал. Q>«Что-то ты тут бредишь »
Ну и? ) Или ты по прежнему хочешь попытаться доказать, что та фраза была не бредом? )
_>>Теперь тебе осталось только приложить какие-нибудь ссылочки Q>И зачем мне это делать? Я не твой личный Гугл. Я вроде доступно объяснил, что я имел в виду, и почему нет ничего криминального в утверждении, что в навигации, рефакторингах и подсветках ошибок в IDE пользователю помогает компилятор. (Ну или не помогает в случае C++.) У меня ж нет цели убеждать лично тебя За топикстартера страшновато, особенно после перенесения ветки во /flame, где, очевидно, плюсовое лобби сильно как нигде.
Всё очень просто. Если указанная тобой "терминология" является общепринятой (ну мало ли, может это действительно так, а я просто не знал — всякое бывает), то это будет означать, что ты тогда сказал всё корректно, а я просто глупо придрался из-за своего незнания. Если же всё наоборот и данная "терминология" является твоим персональным изобретением (причём скорее всего вчерашней давности), то это будет означать, что ты изначально написал бред, а потом в ответ на моё справедливое замечание ещё и долго пытался оправдать свой бред нелепыми отмазками.
Q>Давай лучше расскажи за `this_thread::sleep_for(1s);` из соседнего трэда (pun intended). Может, лучше сразу `sleep_for(2s);`, чтоб наверочку?
Зачем? Для визуального эффекта достаточно и одной секунды. А больше ни для чего эта строчка не служит (если её убрать, то всё равно всё будет работать корректно).
Q>И, раз уж массив указателей это плохо для кэша, то почему это не плохо для массива moveable-объектов, которые (для реализации move-семантики) реализованы через тот же указатель, только внутри?
У тебя не верное сравнение. Структура объекта очевидно определяется не тем, как его будут хранить в массивах, а его прикладными свойствами. Так что в итоге в варианте использования массива указателей у нас получится массив указателей на объекты содержащие указатель. Кстати, вот именно такая архитектура и является максимально характерной для мира Java/C#.
Что касается кэша, то конечно же любая косвенность снижает его эффективность. Но какие-то самые банальные её уровни предсказатель всё же способен побороть. Но при многоуровневой косвенности эффективная работа кэша умирает сразу. )))
Здравствуйте, Qbit86, Вы писали:
_>>Вообще то move-семантика — это как раз реальная киллер-фича, которая принципиально увеличивает эффективность кода. Причём каких-то даже близких аналогов этой фичи нет ни в одном из мейнстрим языков. Q>Посмотри Rust: https://doc.rust-lang.org/book/ownership.html
И с каких пор Rust стал относиться к мейнстриму? )
P.S. Если что, я давно слежу и за D и за Rust и за Nim. )))
Re[22]: Visual C# vs C++. Надо сравнить перспективы.
Здравствуйте, itslave, Вы писали:
lpd>>Скомпилировал clang++ в linux и запустил этот код и получил undefined behaviour: lpd>>На мой взгляд — обычный C++ это баланс производительностью, удобством и простотой, с возможностью ручного ассемблера. I>Ага, еще С++ кроссплатформенный!
Нуу не стоит путать базовые принципы и недоработку реализации библиотечной функции под одной из платформ. )
Здравствуйте, alex_public, Вы писали:
_>Здравствуйте, Qbit86, Вы писали:
Q>>И, раз уж массив указателей это плохо для кэша, то почему это не плохо для массива moveable-объектов, которые (для реализации move-семантики) реализованы через тот же указатель, только внутри?
_>У тебя не верное сравнение. Структура объекта очевидно определяется не тем, как его будут хранить в массивах, а его прикладными свойствами. Так что в итоге в варианте использования массива указателей у нас получится массив указателей на объекты содержащие указатель. Кстати, вот именно такая архитектура и является максимально характерной для мира Java/C#.
_>Что касается кэша, то конечно же любая косвенность снижает его эффективность. Но какие-то самые банальные её уровни предсказатель всё же способен побороть. Но при многоуровневой косвенности эффективная работа кэша умирает сразу. )))
В кэше не только данные, к которым обращение проходит последовательно, но и данные, к которым недавно было обращание. Причем второй вариант актуален гораздо чаще, чем первый. Кэшировать последовательное обращение нужно скорее для инструкций, чем для данных. Либо, в вычислительных алгоритмах. Но там, скорее всего, будут простые массивы. Пример: я реализовывал алгоритм на простом бинарном графе, и boost::graph работал на 30% медленнее, чем моя структура. Это неплохо, но все равно неприемлемо.
У сложных вещей обычно есть и хорошие, и плохие аспекты.
Берегите Родину, мать вашу. (ДДТ)
Здравствуйте, Qbit86, Вы писали:
V>>Продолжаем откровенно притормаживать. Q>Хамовато.
Ну, сначала мне показалось, что ты просто троллишь.
Q>Навскидку, есть такой класс: Q>
internal class GenericEqualityComparer<T>: EqualityComparer<T> where T: IEquatable<T>
Угу, у которого создание экземпляров происходит через рефлексию.
Офигенный пример обсуждаемого "параметрического полиморфизма".
==============
Ну вот поставь себя на моё место. Как мне на подобные "аргументы" реагировать?
Как на злостный троллинг или как на рассуждения случайного в профессии человека?
V>Угу, у которого создание экземпляров происходит через рефлексию. V>Офигенный пример обсуждаемого "параметрического полиморфизма".
Угу один раз на создание компаратора, который может вызываться миллионы раз V>============== V>Ну вот поставь себя на моё место. Как мне на подобные "аргументы" реагировать? V>Как на злостный троллинг или как на рассуждения случайного в профессии человека?
Улыбнуться над твоими выводами.
Другое дело, что там нет инлайнинга, но например для Linq есть оптимизация уже сейчас
Обновленная цепочка инструментов .NET Native. Эта обновленная цепочка инструментов .NET Native включает несколько оптимизаций для повышения производительности во время выполнения для управляемых приложений UWP в Visual Studio. Этот выпуск включает более 600 исправлений ошибок и функций, соответствующих основным пожеланиям клиентов и повышающих общее качество цепочки инструментов.
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, alex_public, Вы писали:
_>Всё очень просто. Если указанная тобой "терминология" является общепринятой (ну мало ли, может это действительно так, а я просто не знал — всякое бывает), то это будет означать, что ты тогда сказал всё корректно, а я просто глупо придрался из-за своего незнания. Если же всё наоборот и данная "терминология" является твоим персональным изобретением (причём скорее всего вчерашней давности), то это будет означать, что ты изначально написал бред, а потом в ответ на моё справедливое замечание ещё и долго пытался оправдать свой бред нелепыми отмазками.
По сути он прав, все фичи IDE реализуются внутренним "компилятором", разве что без бекенда. Это буквоедство с вашей стороны, особенно после объяснения, что имелось в виду.
Здравствуйте, vdimas, Вы писали:
Q>>Навскидку, есть такой класс: Q>>
internal class GenericEqualityComparer<T>: EqualityComparer<T> where T: IEquatable<T>
V>Угу, у которого создание экземпляров происходит через рефлексию. V>Офигенный пример обсуждаемого "параметрического полиморфизма".
Внутренний говнометод с рефлексией нужен только для создания дефолтного компарера. Никто не мешает объявить своего наследника от этого абстрактного класса и создавать его обычным образом. Пардон, перепутал — речь же о внутреннем классе. Таки да, его создать можно только рефлексией.