Re[25]: Java vs C# vs C++
От: Evgeny.Panasyuk Россия  
Дата: 08.10.15 13:27
Оценка:
Здравствуйте, ·, Вы писали:

dot>>>Во-вторых, попробуй такой трюк проверни со включенным security manager, запретить const_cast же — невозможно.

EP>>Возможно. Даже если опасаешься false positives/negatives grep'а — то легко написать простейший верификатор на базе Clang AST Matchers.
dot>Задоблаешься. Скажем, частенько при интеграции с другими библиотеками, особенно C, может вылезти:
dot>
dot>Obj *obj2 = (Obj *)obj2;
dot>

dot>И нифига ненаверифицируешь.

Старый cast легко отлавливается компилятором, например опция GCC -Werror-old-style-cast

dot>И вообще, никакая это не верификация, а статический анализ.


Это верификация соответствия требованиям.

dot>>>В-третьих, вот так в C++ писать уже можно?

EP>>В Java у volatile семантика другая нежели чем у C++. Для этой же цели используются std/boost::atomic. То есть будет не volatile ImmutableClass *, а atomic<ImmutableClass *>.
dot>О, наконец-то стало можно. Если не ошибаюсь, в С++ это появилось c 2011, в Яве же с 2004.

В стандарте C++11 появились std::atomic, memory model, да и вообще понятие потока.
Библиотечные же реализации работают и в C++1998.
Re[24]: Java vs C# vs C++
От: · Великобритания  
Дата: 08.10.15 13:28
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

dot>>ООМ везде можно получить.

EP>Я описываю конкретный case, который есть при использовании GC, и которого нет при использовании scope-based lifetime.
Понятно, что С++ позволяет сделать больше, чем Java. Но GC это очень хороший алгоритм и даёт много преимуществ в широком классе задач, в т.ч. low latency.

EP>Не надо оправдываться абстрактными "OOM везде можно получить" — я так тоже умею: "везде можно получить расстрел памяти, даже при использовании Java"

Расстрел памяти в Java? Как???

dot>>>>Можно, конечно, такое же соорудить и в C++, но это будет закат солнца вручную.

EP>>>Почему вручную-то? Если есть такой развесистый граф владения — то и очищай его по частям, автоматически.
dot>>По каким частям?
EP>Например очищать фиксированное количество объектов за раз, оставшиеся ставить в очередь.
Фиксированное чем? Как узнать сколько за раз?

dot>>Как эти части определить?

EP>Как того требует задача. Если нужно ограничить время — то соответственно засекаешь время/тики, или что там удобнее.
Время чего? Вот у тебя
smartPtr.release(); // упс, заняло 300ms, хотя обычно занимает 3us. Нам не повезло оказаться последним юзером объекта и граф объектов оказался больше обычного.

Куда именно ты поставишь тики?

dot>>В каком порядке очищать?

EP>Например в порядке очереди.
Как выстоить в очередь граф объектов?

dot>>Когда ответишь на эти вопросы и многие другие, то переизобретёшь современный gc.

EP>Нет, это неверно. Задача GC в первую очередь отличить reachable от unreachable объектов. А уж делать reclaim порциями, или за один присест — это уже отдельное свойство, причём ортогональное наличию/отсутствию GC.
GC в Java это целый комплекс алгоритмов с тучей настроек. Задача — освобождать память от unreachable объектов, а не просто "отличить".

EP>И, кстати, для C++ возможен и runtime'овый GC (прям в стандарте есть специальное API), и библиотечный (я даже как-то делал for fun).

Но как? Precise GC принципиально невозможен. С safepoints тоже проблемы. Дизайн Java позволяет использовать гораздо более мощные алгоритмы GC, чем те, которые доступны в C++ коде.

EP>>>Да и возникают они в Java на порядки чаще чем в C++. Элементарный пример: массив объектов, агрегирующих другие объекты, агрегирующих другие ... — вполне типичная ситуация. На Java будет тот самый развесистый граф, а на C++ может быть просто по сути один вектор освобождающийся за O(1) — так как value semantics.

dot>>Сам же написал "GC линеен от количества N живых объектов", т.е. сдохший шмат графа можно освобождать также за примерно O(1).
EP>При этом сделав O(N) обход живых объектов, которого нет в случае с C++
В YG это N малО, а OG обходится не часто, и обычно минимально влияя на основные потоки. (Мы рассматриваем low latency, когда память не забита под завязку, конечно).
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[24]: Java vs C# vs C++
От: · Великобритания  
Дата: 08.10.15 13:38
Оценка:
Здравствуйте, T4r4sB, Вы писали:

TB>·>Т.е. неиндусы — никогда не ошибаются? Даже дело не в том, что ошибаются или нет — проверить никак нельзя.

TB>То есть С++ требовательнее к дисциплине программиста. Это его недостаток. Что не так?
Дело не в дисциплине, а в гарантии правильности. Если у тебя есть некий критичный кусочек кода — его можно проанализировать очень внимательно (или даже доказать) и быть уверенным, что именно он так и отработает. В случае С++ — это невозможно принципиально — расстрел памяти ведёт к непредсказуемым результатам любой части кода.

TB>·>запретить const_cast же — невозможно.

TB>Это уныло. Ругать язык за то, что в нём можно сделать диверсию — это уныло, потому что диверсию можно сделать в любом языке, что я и показал. И говорить, что якобы в одном языке обнаружить такую откровенную (как конст_каст) диверсию проще, чем в другом — это тоже уныло.
Знаю, что уныло, но факт остаётся фактом. И не диверсия, а просто ошибка.

TB>·>В-третьих, вот так в C++ писать уже можно?

TB>А проблема-то в чём? Расскажи, почему в жабе так можно делать (с локами? без них?), а в С++ нельзя? Что за хрень эти иммутабельные классы? Аааа, я понял, в жабе нету типа "указатель на константу", поэтому "иммутальные классы" преподносятся, как откровение.
Укзатель на константу? Это оно?
Data openFile(const Path &path)
{
  if(!isAccessAllowed(path)) throw InvalidAccess();
  return readData(path);
}

Проблему сам найдёшь? Откровение открылось?

Иммутабельный класс это значит, что его можно использовать в любое время из любого треда и быть уверенным, что результат будет тем же.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[21]: Java vs C# vs C++
От: Evgeny.Panasyuk Россия  
Дата: 08.10.15 13:44
Оценка: +1
Здравствуйте, ·, Вы писали:

dot>>>Ролик не смотрел, дома посмотрю... Но могу заметить, что эти все нарезки обычно делаются в довольно ограниченной области кода. И все эти порчи данных довольно изолированы (или как минимум изолируемы).

EP>>Да, но мы-то обсуждаем именно такой случай, именно эту самую область кода. И эта ручная error-prone нарезка на структуры, отказ от GC и т.п. — по сути выливается в уровень ниже чем C, и в результате приводит к вполне ожидаемым ошибкам: http://rsdn.ru/forum/philosophy/6201205.1
Автор: Evgeny.Panasyuk
Дата: 02.10.15

dot>Заметь, эта ошибка в C++,

Ошибка в Java варианте.

dot>т.е. к яве отношения не имеет. А java-specific никакой проблемы не представляет


Это именно Java-specifc ошибка.
Так как нет структур (а например с классами вместо структур на C# этот пример тормозит ~80x) — ему пришлось
Автор: mik1
Дата: 02.06.15
вместо массива Complex, руками нарезать массив double на Complex, и руками сплавлять обход и перемножение элементов массива в одну операцию. И именно в этом месте у него вылезла ошибка.
Re[24]: Java vs C# vs C++
От: · Великобритания  
Дата: 08.10.15 13:47
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

dot>>Мало того, тот кому не повезло освобождать ссылку последним — не придётся тратить ВНЕЗАПНО время на освобождение,

EP>Пусть просто поставит в очередь, делов-то
Поставит что? Сразу весь развесистый граф? А если надо только часть освободить? Ставить каждый самый мелкий объект? А очереди не поплохеет? В общем опять, закат gc вручую.

EP>>>На Java кстати какое решение можешь предложить?

dot>>На java память ресурс другого типа. "Освобождать память" там нельзя.
EP>А я поэтому и сказал конкретно "ресурс", а не просто "объект". Да и память не ресурс только если она не ограниченна — упрёшься в предел, получишь удар по latency, на который постоянно ссылаешься.
В low latency единственный ресурс обычно память. Из LL кода никто в своём уме коннекты к БД не открывает, с SOAP сервисам не обращается.

dot>>А для ресурсов в общем случае — наследники java.lang.ref.Reference.

EP>Каким образом они обеспечат prompt finalization?
А надо? А зачем вообще ресурсы обязательно освобождать из финалайзеров? Я не понял какую задачу ты описываешь.

EP>>>На них точно также получаются локи. Чтобы их не было, нужно использовать например lock-free / wait-free схемы.

dot>>Ну да... Только, как мне кажется. эти схемы гораздо проще если есть gc.
EP>При GC чуть проще реализация lockfree структур данных, за счёт ABA, но при этом сами GC в большинстве своём не lockfree (lockfree GC видел только в статьях) — то есть тут уже большой терминологический вопрос, остаётся ли структура данных lockfree при не non-lockfree GC
Если локи расставляются сами компилятором и лочится на предсказуемое время — почему бы и нет.

EP>Да и такие структуры должны реализовывать профессионалы своего дела, так как это трудная/опасная тема.

В том то и дело. Это уже и реализовали в виде JVM — бери, да используй, а не изобретай велосипед.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[25]: Java vs C# vs C++
От: T4r4sB Россия  
Дата: 08.10.15 13:48
Оценка:
Здравствуйте, ·, Вы писали:

·>Дело не в дисциплине, а в гарантии правильности. Если у тебя есть некий критичный кусочек кода — его можно проанализировать очень внимательно (или даже доказать) и быть уверенным, что именно он так и отработает. В случае С++ — это невозможно принципиально — расстрел памяти ведёт к непредсказуемым результатам любой части кода.


Да-да, я это слышал, это из первой лекции для студентов "недостатки С++". /_-

·>Знаю, что уныло, но факт остаётся фактом. И не диверсия, а просто ошибка.


Случайно сделать 10 ошибок в слове "int" и получить "const_cast"? Или как?

·>Проблему сам найдёшь? Откровение открылось?


Нет, проблемы не вижу, кроме случая, когда в команде бардак и разработчики диверсанты, "случайно" пишущие const_cast, срущие в данные, которые другой поток считает константными, делящие на ноль и невзначай вставляющие в код команду форматирования винчестера.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[2]: Java vs C# vs C++
От: T4r4sB Россия  
Дата: 08.10.15 13:59
Оценка:
Здравствуйте, A13x, Вы писали:

A>Для желающих проверить на практике — предлагаю желающим реализовать простейший интерпретатор нетипизированного лямбда исчисления на С++ (ну то есть REPL который бы понимал что-то вроде такого) и сравнить его быстродейтвие с тем, что можно реализовать на яве (мой вариант меньше 500 строк и по быстродействию уделывает известные мне интерпретаторы scheme). Насколько я себе представляю возможные реализации — на стресс тестах будет большое количество виртуальных вызовов и большое количество выделений памяти под мелкие объекты.


Дык можно запилить свой хитрый аллокатор для мелких объектов просто, а подвох-то в чём?
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[12]: Java vs C# vs C++
От: · Великобритания  
Дата: 08.10.15 14:00
Оценка:
Здравствуйте, PM, Вы писали:

PM>>> Короче, сплошной <троллейбус из буханки хлеба.jpeg>

PM>·>Собственно сейчас в моде Zing JVM, там задержки не более 10ms, в основном ~100us.
PM>·>Писать такое на C++... неее... проще застрелиться.
PM>·>А перезапуск нужен не для gc, а чтобы на диск состояние скинуть, ибо использовать классические СУБД — теоретически невозможно.
PM>Задержка 10ms может быть неприемлемой в некоторых задачах, в том числе и в биржевых системах.
Я знаю, я говорю, что 10ms это уже проблема — на которую тут же заводится bug report.

PM>Состояние на диск постоянно скидывается в LMAX в отдельном потоке в файл журнала. И разработчики LMAX повоевали и здесь чтобы добиться предсказуемого результата. Ну и для сетевого I/O наверняка использовали какой-нибудь NIO.

В журнал скидываются транзакции (дельты), а раз в день делается снапшот состояния.
Война была, да и до сих пор ведётся не с java, а с архитектурой и железом. 90% тех решений подходит и для С++.

PM>Я почитал ваши сообщения в ветке. Ещё одна иллюстрация, что люди не из мира C++ продолжают верить в мифы 15-20 летней давности. Авторы LMAX скорее всего тоже подумали: "Писать такое на C++... неее... проще застрелиться" и взяли хорошо известный им и широко распространённый инструмент. Хорошо, что при этом они не застрелились

На плюсах есть куски или нативные либы, но как-то постепенно перетекает всё в java. Ибо работает так же, а добавляется куча преимуществ (см ролик http://rsdn.ru/forum/philosophy/6205646.1
Автор: Evgeny.Panasyuk
Дата: 07.10.15
)
Как в одно время был процесс переползания с ассемблеров на фортран, на С, на С++, теперь вот java. Конечно, на arduino яву не запустишь, но нишу LL она уверенно отвоёвывает.

PM>Часть кода, кстати, открыта: https://github.com/LMAX-Exchange/disruptor и выглядит на мой взгляд over engineering. Хотя, может для Java мира это нормально

Видимо поэтому этот over engineering стырили https://code.google.com/p/disruptor-cpp/ https://github.com/disruptor-net/Disruptor-net Как видишь — дело не в языке, а в архитектуре.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[30]: Java vs C# vs C++
От: Evgeny.Panasyuk Россия  
Дата: 08.10.15 14:12
Оценка:
Здравствуйте, Ikemefula, Вы писали:

I>>>>>"Как на Си" это в первую очередь вещи, где нужен полный контроль над временем выполнения, не "хрен знает сколько" а скажем "не более 8000 тактов".

EP>>>>Это не "как на Си". Контроль над временем вообще ортогонален "как на Си".
I>>>Наоборот.
EP>>Аргументированно
I>Ну и логика
I>Вот это аргумент: 'Это не "как на Си"'
I>А вот это — 'Это "как на Си"' — уже нет
I>Браво !

Врёшь же. Я конкретно сказал что контроль над временем ортогонален "как на Си".

I>>>ибо в low-latency работает в т.ч. и джава.

EP>>На Java можно в том числе создавать быстрый код. Затратно, но можно.
I>Настолько быстрый, как С++ это невозможно. И тем не менее джава есть в low latence. А следовательно твой

Настолько же быстрый — да, вряд ли. А вот разница в десятки процентов (не считая векторизацию и т.п.) вполне достижима. Огромной ценой, но тем не менее.

EP>>>>На C та часть которая "не только" (то есть опциональная) — она не реализуема.

I>>>Реализуема, только иначе.
EP>>Расшифруй.
I>Это значит, что те же задачи решаются и в Си, за доказательством смотри полноту по тьюрингу

Причём тут полнота по Тьюрингу? В данном месте обсуждаем использование ref-counting там где в этом нет необходимости, то есть для подстраховки.

EP>>А ты представляешь как реализуется ref-counting в C++11?

I>А при чем здесь 11 ?

При том что на нём передёргиваний счётчиков на порядки меньше. И соответственно меньше overhead'а привнесённого непосредственно подсчётом ссылок.

I>Есть куча кода написаного в тысячах контор:

I>"Зануление счетчика, вызов деструктора, который вызывает зануление другого счетчика, который вызывает деструктор,и тд и тд"

В этом плане ref-counting практически никаких тормозов не добавляет (пара лишних операций перед очисткой) — подобная каскадная очистка есть и без него.
Re[31]: Java vs C# vs C++
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 08.10.15 14:27
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

I>>Вот это аргумент: 'Это не "как на Си"'

I>>А вот это — 'Это "как на Си"' — уже нет
I>>Браво !

EP>Врёшь же. Я конкретно сказал что контроль над временем ортогонален "как на Си".


Это просто твоё мнение, ничем не аргументированое. Я его услышал, выдал симметричное, только мне понадобилось всего слово для этого.

I>>Настолько быстрый, как С++ это невозможно. И тем не менее джава есть в low latence. А следовательно твой

EP>Настолько же быстрый — да, вряд ли. А вот разница в десятки процентов (не считая векторизацию и т.п.) вполне достижима. Огромной ценой, но тем не менее.

То есть, в кратце, незачем выжимать сок из Сишного кода, если код на десятки процентов медленнее справляется с работой. Правильно ?

EP>>>Расшифруй.

I>>Это значит, что те же задачи решаются и в Си, за доказательством смотри полноту по тьюрингу
EP>Причём тут полнота по Тьюрингу? В данном месте обсуждаем использование ref-counting там где в этом нет необходимости, то есть для подстраховки.

Из этой самой полноты следует "в этом нет необходимости, то есть для подстраховки"

EP>При том что на нём передёргиваний счётчиков на порядки меньше. И соответственно меньше overhead'а привнесённого непосредственно подсчётом ссылок.


А в Киеве дядька.

I>>Есть куча кода написаного в тысячах контор:

I>>"Зануление счетчика, вызов деструктора, который вызывает зануление другого счетчика, который вызывает деструктор,и тд и тд"

EP>В этом плане ref-counting практически никаких тормозов не добавляет (пара лишних операций перед очисткой) — подобная каскадная очистка есть и без него.


Твоя "подстраховка", требует ресурсов. Каскадная очистка — часть этой самой подстраховки. Вместо явной логики "вычислить и освободить явно" выбираем неявную "пусть деструкторы срабатывают каскадом по цепочке, авось пронесёт"
Re[20]: Java vs C# vs C++
От: · Великобритания  
Дата: 08.10.15 14:45
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>>>Escape analysis вообще из другой оперы. Это например про аллокации объектов на стэке вместо кучи — в таких случаях никакой unique_ptr не нужен

EP>>>Более того аллокация на стэке — это default для C++, и работает даже в случаях escape.
dot>>Не обязательно на стеке, ещё есть thread local heap.
dot>>Код может быть очень развесистохитрым, а unique_ptr выведется сам, как результат EA.
EP>И каким образом у тебя получился тут unique_ptr?
Если VM оптимизатор видит, что объект используется только в одном месте, он переносит ссылку на стек, т.е. по сути выводит unique_ptr.

EP>>>Что? Причём тут теперь weak_ptr? Уже какая-то каша пошла.

dot>>shared_ptr у треда-владельца, а "зависимые" — имеют weak_ptr.
EP>Как weak_ptr относится к дискуссии?
Как я понял, ты предлагаешь выделить один тред как владелец объекта, т.е. тот, кто держит shared_ptr, а другие треды — просто пользователи объекта, им отдаётся weak_ptr (не голые же указатели передавать?!).

dot>>>>Последствия обращения к неверным указателям — серьёзнее. Не простой краш, а хз что.

EP>>>А например OOM — тоже вполне серьёзно
dot>>ООМ происходит в яве ровно так же как и в плюсах. Всё то же самое.
EP>OOM он конечно везде OOM, но причины наступления бывают разные
OOM не кидается в случае если gc есть что освободить.

dot>>Отказываться от классов? Это как? В смысле раскладывать данные по массивам? Массивы не отказ от классов, а от полей классов. Эта техника не специфична для Java, в С++ тоже так делают:

dot>>http://programmers.stackexchange.com/questions/246474/data-oriented-design-impractical-with-more-than-1-2-structure-members
EP>Нет, именно от классов. То что ты привёл это иногда называется Structure of Arrays, в C++ кстати я такую трансформацию реализовывал в библиотечном виде, то есть раскидывание происходит автоматически.
EP>Я же говорю про обычные структуры, в Java нет даже их. То есть положить в один массив плотно друг к другу данные вида:
EP>
EP>struct Foo
EP>{
EP>    double a;
EP>    int b;
EP>    char c, d;
EP>};
EP>
напрямую не получится, и это существенный источник тормозов. В зависимости от ситуации медленнее может быть на несколько порядков. На ровном месте вырастают целые деревья индерекций.

EP>Обходится например через огород low-level эмуляции на чём-то типа ByteBuffer.
Делаешь класс (зачем от классов то отказываться?!)
class FooArray
{
   ByteBuffer data;
   getA();setA();
   getB();setB();
   getC();setC();
   getD();setD();
}

Да, выглядит некрасиво, но обычно составляет <0.1% кода и сложностей никаких не доставляет. Почему-то я уверен, что "трансформацию реализовывал в библиотечном виде" будет выглядеть гораздо хуже и иметь довольно нетривиальный код.

EP>>>Это фантазии, ничем не обоснованные.

EP>>>При использовании Java в таких случаях отказываются и от GC и от классов, и нарезают вручную массивы байт на структуры. Получить порчу данных в таком случае на порядки проще чем на высокоуровневом C++.
EP>>>Вот конкретный пример (первые минут двадцать)
dot>>Посмотрел начало ролика. В общем там неплохо сказано — быстрое ядро относительно маленькое, зато обвязка — на порядок больше. Поэтому в целом и получается этот порядок.
EP>Субъектива он там нагнал предостаточно (ЕМНИП было даже что-то типа "для нормального C++ кода, нужны те кто ковыряется внутри кода GCC").
EP>Давай обсуждать объективные вещи.
Так вполне объективно: LL ядро — один сервис, обвязка вокруг него — ещё пол сотни.

dot>>И, кстати, я заметил, что java-specific там практически ничего не было. Основной упор именно на то, что надо понимать как работает железо, а какой язык — не важно, техники отличаются деталями реализации, принцип же тот же.

EP>Понимать как работает железо обязательно нужно. Также нужно понимать как отображаются конструкции языка в железо — и вот с этим у Java проблемы, для быстрого кода приходится отказываться даже от элементарных абстракций и городить low-level код, который даже ниже уровень чем то что есть в языке C.
Да нет каких-то сверх-проблем. Да, нужно писать код определённым образом, реализовывать определённые решения, но это верно для любого оптимизируемого кода на любом языке. Java в этом плане ничуть ни лучше, ничуть не хуже, чем C++.

dot>>А. Да. Не так посмотрел, там оказывается специализации под разные стратегии.

dot>>В общем да. Да, на плюсах можно делать то же, что и в Яве. Ведь Ява на плюсах написана. Но из-за арифметики указателей и прочего нормальный gc сделать всё равно не выйдет, только всякие ref counting и прочее.
EP>Я делал библиотечный копирующий GC for fun — простой вариант с одним поколением уместился в несколько сотен строк. Естественно есть ограничения, но тем не менее.
EP>AFAIR, в Mozzila используют библиотечный GC в местах interop'а с JS.
Простые варианты и делаются просто. А когда ты начинаешь делать не for fun, а серьёзно — становится всё плохо.
Mozilla не LL, а JS вообще однопоточный. В общем, всё на порядки проще.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[26]: Java vs C# vs C++
От: · Великобритания  
Дата: 08.10.15 14:50
Оценка:
Здравствуйте, Ikemefula, Вы писали:

I>>>·>gc прощает гораздо больше ошибок. И самое страшное что может случиться — тормоза. Без него — всё что угодно, и тормоза, и порча памяти, и утечки.

I>>>Самое страшное — твою софтину для биржи на джаве никто не купит. Отсюда ясно, что часть софта в принципе никто даже не станет пытаться писать на джаве.
I>·>Расскажи это как миниимум упомянутым dxFeed и LMAX.
I>Есть куча проектов, которые загнулись из за того, что так и не смогли сбороть этот GC.
А конкретнее? Ни одного С++ проекта не загнулась из-за сложности кода?

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

Ещё раз. GC составляет O(1) проблем LL, самая жуть это железо и ОС. Глючный сетевой кабель — и 300мс задержка только в путь, такое GC и не снилось.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[26]: Java vs C# vs C++
От: · Великобритания  
Дата: 08.10.15 14:57
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>>>Возможно. Даже если опасаешься false positives/negatives grep'а — то легко написать простейший верификатор на базе Clang AST Matchers.

dot>>Задоблаешься. Скажем, частенько при интеграции с другими библиотеками, особенно C, может вылезти:
dot>>
dot>>Obj *obj2 = (Obj *)obj2;
dot>>

dot>>И нифига ненаверифицируешь.
EP>Старый cast легко отлавливается компилятором, например опция GCC -Werror-old-style-cast
Ну пусть будет reinterpret_cast<Obj *>(obj) какая разница-то?

dot>>И вообще, никакая это не верификация, а статический анализ.

EP>Это верификация соответствия требованиям.
Под верификацией обычно понимается проверка формальными методами. А так — анализ, тестирование.

EP>>>В Java у volatile семантика другая нежели чем у C++. Для этой же цели используются std/boost::atomic. То есть будет не volatile ImmutableClass *, а atomic<ImmutableClass *>.

dot>>О, наконец-то стало можно. Если не ошибаюсь, в С++ это появилось c 2011, в Яве же с 2004.
EP>В стандарте C++11 появились std::atomic, memory model, да и вообще понятие потока.
EP>Библиотечные же реализации работают и в C++1998.
Ну так нечестно. А то я скажу, что "gc можно отключить в java" если использовать библиотеки с off-heap.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[25]: Java vs C# vs C++
От: Evgeny.Panasyuk Россия  
Дата: 08.10.15 15:01
Оценка:
Здравствуйте, ·, Вы писали:

EP>>Не надо оправдываться абстрактными "OOM везде можно получить" — я так тоже умею: "везде можно получить расстрел памяти, даже при использовании Java"

dot>Расстрел памяти в Java? Как???

Элементарно. Её может расстрелять сторонняя native библиотека, причём даже не из-за бага в самой библиотеке, а потому что Java код нарушил предусловия. Или например может расстрелять свой же Runtime — гарантии нет
Это аргумент примерно того же порядка что и "OOM везде можно получить" в ответ на описание конкретного use-case'а.

dot>>>Как эти части определить?

EP>>Как того требует задача. Если нужно ограничить время — то соответственно засекаешь время/тики, или что там удобнее.
dot>Время чего? Вот у тебя
dot>
dot>smartPtr.release(); // упс, заняло 300ms, хотя обычно занимает 3us. Нам не повезло оказаться последним юзером объекта и граф объектов оказался больше обычного.
dot>


Не обязательно удалять весь граф сразу, можно по одному узлу, граф-остаток ставить в очередь.

dot>>>В каком порядке очищать?

EP>>Например в порядке очереди.
dot>Как выстоить в очередь граф объектов?

Например в деструкторе smart-pointer'а не сразу удалять, а ставить в очередь.

dot>>>Когда ответишь на эти вопросы и многие другие, то переизобретёшь современный gc.

EP>>Нет, это неверно. Задача GC в первую очередь отличить reachable от unreachable объектов. А уж делать reclaim порциями, или за один присест — это уже отдельное свойство, причём ортогональное наличию/отсутствию GC.
dot>GC в Java это целый комплекс алгоритмов с тучей настроек. Задача — освобождать память от unreachable объектов, а не просто "отличить".

А ещё он внутри делает сложение целых чисел. Из этого не следует что сложение целых чисел это "переизобретание современного GC".

EP>>И, кстати, для C++ возможен и runtime'овый GC (прям в стандарте есть специальное API), и библиотечный (я даже как-то делал for fun).

dot>Но как? Precise GC принципиально невозможен.

Возможен. Заводится отдельная GC Heap, все указатели на элементы внутри этой кучи заворачиваются в gc_ptr<T>.
Отличать root от не root можно разными способами. Например если сам объект-указатель типа gc_ptr находится не в этой куче — то это root.
AFAIR, нечто подобное используется в SpiderMonkey.

EP>>>>Да и возникают они в Java на порядки чаще чем в C++. Элементарный пример: массив объектов, агрегирующих другие объекты, агрегирующих другие ... — вполне типичная ситуация. На Java будет тот самый развесистый граф, а на C++ может быть просто по сути один вектор освобождающийся за O(1) — так как value semantics.

dot>>>Сам же написал "GC линеен от количества N живых объектов", т.е. сдохший шмат графа можно освобождать также за примерно O(1).
EP>>При этом сделав O(N) обход живых объектов, которого нет в случае с C++
dot>В YG это N малО, а OG обходится не часто,

Чем больше N — тем чаще. В любом случае это не O(1).

dot>и обычно минимально влияя на основные потоки.


Memory throughput не бесконечная, более того — часто является bottleneck'ом. GC во время обхода интенсивно использует память, сужая этот bottleneck.
Re[26]: Java vs C# vs C++
От: · Великобритания  
Дата: 08.10.15 15:17
Оценка:
Здравствуйте, T4r4sB, Вы писали:

TB>·>Дело не в дисциплине, а в гарантии правильности. Если у тебя есть некий критичный кусочек кода — его можно проанализировать очень внимательно (или даже доказать) и быть уверенным, что именно он так и отработает. В случае С++ — это невозможно принципиально — расстрел памяти ведёт к непредсказуемым результатам любой части кода.

TB>Да-да, я это слышал, это из первой лекции для студентов "недостатки С++". /_-
И с тех пор ты никогда в жизни не расстрелял память или не видел, когда вполне дисциплинированый дев расстреливал?

TB>·>Знаю, что уныло, но факт остаётся фактом. И не диверсия, а просто ошибка.

TB>Случайно сделать 10 ошибок в слове "int" и получить "const_cast"? Или как?
const_cast не единственный способ потерять константность.

TB>·>Проблему сам найдёшь? Откровение открылось?

TB>Нет, проблемы не вижу, кроме случая, когда в команде бардак и разработчики диверсанты, "случайно" пишущие const_cast, срущие в данные, которые другой поток считает константными, делящие на ноль и невзначай вставляющие в код команду форматирования винчестера.
В ядре линуха такие баги находили (а там, видимо бардак и диверсанты).
Вот поэтому и не нужно считать константным, а тупо использовать иммутабельный тип (что при наличии деструкторов в языке сделать невозможно).
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[25]: Java vs C# vs C++
От: Evgeny.Panasyuk Россия  
Дата: 08.10.15 15:24
Оценка:
Здравствуйте, ·, Вы писали:

dot>>>Мало того, тот кому не повезло освобождать ссылку последним — не придётся тратить ВНЕЗАПНО время на освобождение,

EP>>Пусть просто поставит в очередь, делов-то
dot>Поставит что? Сразу весь развесистый граф? А если надо только часть освободить? Ставить каждый самый мелкий объект? А очереди не поплохеет?

Не каждый объект, а те которые не успеваем освободить.

EP>>>>На Java кстати какое решение можешь предложить?

dot>>>На java память ресурс другого типа. "Освобождать память" там нельзя.
EP>>А я поэтому и сказал конкретно "ресурс", а не просто "объект". Да и память не ресурс только если она не ограниченна — упрёшься в предел, получишь удар по latency, на который постоянно ссылаешься.
dot>В low latency единственный ресурс обычно память.

Сильное утверждение. Да и это проблема ко всему относится, а не только к low latency.

dot>Из LL кода никто в своём уме коннекты к БД не открывает, с SOAP сервисам не обращается.


Файлы не открывают? Соединения не устанавливают?

dot>>>А для ресурсов в общем случае — наследники java.lang.ref.Reference.

EP>>Каким образом они обеспечат prompt finalization?
dot>А надо?

Надо, это задача.

dot>А зачем вообще ресурсы обязательно освобождать из финалайзеров?


Освобождай откуда угодно, но покажи как это реализуется в Java.

dot>Я не понял какую задачу ты описываешь.


Ту же самую, с потоками, при завершении последнего нужно освободить ресурс.

EP>>>>На них точно также получаются локи. Чтобы их не было, нужно использовать например lock-free / wait-free схемы.

dot>>>Ну да... Только, как мне кажется. эти схемы гораздо проще если есть gc.
EP>>При GC чуть проще реализация lockfree структур данных, за счёт ABA, но при этом сами GC в большинстве своём не lockfree (lockfree GC видел только в статьях) — то есть тут уже большой терминологический вопрос, остаётся ли структура данных lockfree при не non-lockfree GC
dot>Если локи расставляются сами компилятором и лочится на предсказуемое время — почему бы и нет.

Потому что lock'и это не lockfree, принципиально. Смотри определение. Lockfree это прежде всего некоторые гарантии, а не например скорость — скорость вообще может быть меньше.
Да и кто сказал что время предсказуемо? Например GC заснул захватив lock, остальные ждут. Тут желательно хотя бы obstruction free

EP>>Да и такие структуры должны реализовывать профессионалы своего дела, так как это трудная/опасная тема.

dot>В том то и дело. Это уже и реализовали в виде JVM — бери, да используй, а не изобретай велосипед.

А я предлагал изобретать? Я сказал что ABA проще решается при использовании GC, решать её при этом самому не обязательно.
Re[32]: Java vs C# vs C++
От: Evgeny.Panasyuk Россия  
Дата: 08.10.15 15:36
Оценка:
Здравствуйте, Ikemefula, Вы писали:

EP>>Врёшь же. Я конкретно сказал что контроль над временем ортогонален "как на Си".

I>Это просто твоё мнение, ничем не аргументированое.

Это аргумент. Ты можешь быть согласен с ним или нет.

I>Я его услышал,


Ты если не согласен с аргументом, или не понял, то так и скажи, и попроси разъяснения.

I>выдал симметричное, только мне понадобилось всего слово для этого.


Ты вообще не выдал никакого аргумента.

EP>>>>Расшифруй.

I>>>Это значит, что те же задачи решаются и в Си, за доказательством смотри полноту по тьюрингу
EP>>Причём тут полнота по Тьюрингу? В данном месте обсуждаем использование ref-counting там где в этом нет необходимости, то есть для подстраховки.
I>Из этой самой полноты следует "в этом нет необходимости, то есть для подстраховки"

Это
Задача была сделать подстраховку, я сказал что такая подстраховка не реализуема на C, ты сказал что "реализуема, только иначе", а теперь говоришь суть реализации в том что в этом нет необходимости

EP>>При том что на нём передёргиваний счётчиков на порядки меньше. И соответственно меньше overhead'а привнесённого непосредственно подсчётом ссылок.

I>А в Киеве дядька.

То есть ты не понимаешь в чём тут отличие у C++11

I>>>Есть куча кода написаного в тысячах контор:

I>>>"Зануление счетчика, вызов деструктора, который вызывает зануление другого счетчика, который вызывает деструктор,и тд и тд"
EP>>В этом плане ref-counting практически никаких тормозов не добавляет (пара лишних операций перед очисткой) — подобная каскадная очистка есть и без него.
I>Твоя "подстраховка", требует ресурсов. Каскадная очистка — часть этой самой подстраховки. Вместо явной логики "вычислить и освободить явно" выбираем неявную "пусть деструкторы срабатывают каскадом по цепочке, авось пронесёт"

Ещё раз, эта каскадная очистка была бы и без ref-counting. Understand?
Re[21]: Java vs C# vs C++
От: Evgeny.Panasyuk Россия  
Дата: 08.10.15 16:31
Оценка:
Здравствуйте, ·, Вы писали:

EP>>>>Escape analysis вообще из другой оперы. Это например про аллокации объектов на стэке вместо кучи — в таких случаях никакой unique_ptr не нужен

EP>>>>Более того аллокация на стэке — это default для C++, и работает даже в случаях escape.
dot>>>Не обязательно на стеке, ещё есть thread local heap.
dot>>>Код может быть очень развесистохитрым, а unique_ptr выведется сам, как результат EA.
EP>>И каким образом у тебя получился тут unique_ptr?
dot>Если VM оптимизатор видит, что объект используется только в одном месте, он переносит ссылку на стек, т.е. по сути выводит unique_ptr.

И не в покер, а в преферанс. И не выиграл, а проиграл.
И не ссылку, а сам объект. И не unique_ptr, а просто стэковый объект.

EP>>>>Что? Причём тут теперь weak_ptr? Уже какая-то каша пошла.

dot>>>shared_ptr у треда-владельца, а "зависимые" — имеют weak_ptr.
EP>>Как weak_ptr относится к дискуссии?
dot>Как я понял, ты предлагаешь выделить один тред как владелец объекта, т.е. тот, кто держит shared_ptr, а другие треды — просто пользователи объекта, им отдаётся weak_ptr (не голые же указатели передавать?!).

Именно голые не владеющие указатели — владелец то переживёт всех. Вполне обычная/нормальная/стандартная практика
Smart-pointer'ы прежде всего помогают избавиться от голых владеющих указателей, а не от того что ты подумал.

dot>>>>>Последствия обращения к неверным указателям — серьёзнее. Не простой краш, а хз что.

EP>>>>А например OOM — тоже вполне серьёзно
dot>>>ООМ происходит в яве ровно так же как и в плюсах. Всё то же самое.
EP>>OOM он конечно везде OOM, но причины наступления бывают разные
dot>OOM не кидается в случае если gc есть что освободить.

Упёрлись в потолок, GC начинает очень долго освобождать за O(N), отбирая ресурсы у других потоков, общая пропускная способность снижается (забиты каналы памяти, и аллокации происходят медленней), извне приходят всё новые задачи для которых в свою очередь нужна всё новая память, в конце концов либо OOM либо DoS.

dot>>>Отказываться от классов? Это как? В смысле раскладывать данные по массивам? Массивы не отказ от классов, а от полей классов. Эта техника не специфична для Java, в С++ тоже так делают:

dot>>>http://programmers.stackexchange.com/questions/246474/data-oriented-design-impractical-with-more-than-1-2-structure-members
EP>>Нет, именно от классов. То что ты привёл это иногда называется Structure of Arrays, в C++ кстати я такую трансформацию реализовывал в библиотечном виде, то есть раскидывание происходит автоматически.
EP>>Я же говорю про обычные структуры, в Java нет даже их. То есть положить в один массив плотно друг к другу данные вида:
EP>>
EP>>struct Foo
EP>>{
EP>>    double a;
EP>>    int b;
EP>>    char c, d;
EP>>};
EP>>
напрямую не получится, и это существенный источник тормозов. В зависимости от ситуации медленнее может быть на несколько порядков. На ровном месте вырастают целые деревья индерекций.

EP>>Обходится например через огород low-level эмуляции на чём-то типа ByteBuffer.
dot>Делаешь класс (зачем от классов то отказываться?!)

Вот в этом "делаешь" и есть проблема.

dot>
dot>class FooArray
dot>{
dot>   ByteBuffer data;
dot>   getA();setA();
dot>   getB();setB();
dot>   getC();setC();
dot>   getD();setD();
dot>}
dot>


Такой Array и другие контейнеры нужно делать для каждого типа данных. У тебя будут FooArray, BarArray, FooPriorityQueue, BarPriorityQueue и т.д.
Либо как вариант добавлять лишней динамичности, но от неё будут свои тормоза, причём как размеры заранее не известны.

dot>Да, выглядит некрасиво, но обычно составляет <0.1% кода и сложностей никаких не доставляет.


Это одна из главных причин тормозов в языках с превалирующей pointer semantics. Положил класс с несколькими полями-объектами в массив — уже на ровном месте выросло целое дерево индерекций и аллокаций.

dot>Почему-то я уверен, что "трансформацию реализовывал в библиотечном виде" будет выглядеть гораздо хуже и иметь довольно нетривиальный код.


Нет, не хуже, также как и обычный вариант. В реализации — да, код не самый простой, но она пишется один раз.
Да и это же Array of Structures, нужно не так часто. Речь же про то, что в Java же нет самых обычных структур — для быстрого кода это супер-критично, именно поэтому и нарезают вручную.

dot>>>И, кстати, я заметил, что java-specific там практически ничего не было. Основной упор именно на то, что надо понимать как работает железо, а какой язык — не важно, техники отличаются деталями реализации, принцип же тот же.

EP>>Понимать как работает железо обязательно нужно. Также нужно понимать как отображаются конструкции языка в железо — и вот с этим у Java проблемы, для быстрого кода приходится отказываться даже от элементарных абстракций и городить low-level код, который даже ниже уровень чем то что есть в языке C.
dot>Да нет каких-то сверх-проблем. Да, нужно писать код определённым образом, реализовывать определённые решения, но это верно для любого оптимизируемого кода на любом языке. Java в этом плане ничуть ни лучше, ничуть не хуже, чем C++.

Хуже, намного. Разве пример со структурами тебя не убедил? — это реально уровень ниже чем C, на ровном месте. Так это только один аспект.
Быстрый код на C++ можно писать на высоком уровне абстракции — не нужно отказываться ни от замыканий, ни от классов, ни от ФВП и полиморфизма — и при этом он будет давать точно такое же (либо практически такое же) быстродействие как и такой же код написанный на низком уровне вручную — в этом одна из главных фишек C++.
Re[2]: Java vs C# vs C++
От: mrTwister Россия  
Дата: 08.10.15 16:49
Оценка:
Здравствуйте, Nuzhny, Вы писали:

N>P.S. Я уже молчу про центральный пассаж, что bubble sort — это типичный код. Скажите мне пожалуйста, кто из плюсовиков или шарпистов вообще писал хоть какую-нибудь сортировку? А buble sort?


Меня больше позабавило, что сортировка на unsafe указателях — это типичный код на C#
лэт ми спик фром май харт
Re[27]: Java vs C# vs C++
От: Evgeny.Panasyuk Россия  
Дата: 08.10.15 16:51
Оценка:
Здравствуйте, ·, Вы писали:

EP>>>>Возможно. Даже если опасаешься false positives/negatives grep'а — то легко написать простейший верификатор на базе Clang AST Matchers.

dot>>>Задоблаешься. Скажем, частенько при интеграции с другими библиотеками, особенно C, может вылезти:
dot>>>
dot>>>Obj *obj2 = (Obj *)obj2;
dot>>>

dot>>>И нифига ненаверифицируешь.
EP>>Старый cast легко отлавливается компилятором, например опция GCC -Werror-old-style-cast
dot>Ну пусть будет reinterpret_cast<Obj *>(obj) какая разница-то?

1. reinterpret_cast не снимает константность, мы же о ней говорим?
2. ловится тем же grep'ом

dot>>>И вообще, никакая это не верификация, а статический анализ.

EP>>Это верификация соответствия требованиям.
dot>Под верификацией обычно понимается проверка формальными методами. А так — анализ, тестирование.

Это не тестирование точно. Под определение верификации попадает, причём и на рус/eng. Ну да ладно, это уже чистая терминология.

EP>>>>В Java у volatile семантика другая нежели чем у C++. Для этой же цели используются std/boost::atomic. То есть будет не volatile ImmutableClass *, а atomic<ImmutableClass *>.

dot>>>О, наконец-то стало можно. Если не ошибаюсь, в С++ это появилось c 2011, в Яве же с 2004.
EP>>В стандарте C++11 появились std::atomic, memory model, да и вообще понятие потока.
EP>>Библиотечные же реализации работают и в C++1998.
dot>Ну так нечестно.

Почему не честно-то? Например де-юре потоков в языке C++ не было, де-факто были на каждой платформе их поддерживающей, плюс были и есть кроссплатформенные библиотеки типа Intel Threading Building Blocks, Boost.Thread.

dot>А то я скажу, что "gc можно отключить в java" если использовать библиотеки с off-heap.


Так ведь так и делают, работают против языка, убегают от GC, потому что он доставляет вполне конкретные проблемы.

В случае же с boost::thread и т.п. — наоборот работа вместе с языком, а не вопреки ему — std::thread вошёл в стандарт практически в таком же виде, каком он и так был де-факто в библиотеках C++98.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.