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

I>>>>>>Разве не ты говорил про off-heap приседания ?

I>>>>dot>Off-heap не особо нужен в подавляющем большинстве случаев, да и на архитектуру никак не влияет.
I>>>>Off-heap и есть архитектура. Все что ты выделяешь теперь, надо делать через этот off-heap
dot>>>Да какая архитектура блин. Вместо "MyObj obj = new MyObj()" пишешь "MyObj obj = newMyObj()", в общем-то и вся разница по факту.
EP>>А вместо например MyObj[] что?
dot>ну например List<MyObj>

1. На GC всё равно будет висеть граф множества объектов, пусть и меньшего размера.
2. Теперь на этих ссылках будут висеть финализаторы, так? Для того чтобы знать когда очищать off-heap. То есть теперь ко всему прочему ещё и освобождение будет линейным.
3. Лишние индерекции внутри List никуда не делись.


EP>>И кто и как создаст эти newMyObj?

dot>Программист напишет. Притом можно описывать, скажем, интерфейсы, а их имплементации генерить при запуске.

"в общем-то и вся разница по факту." — да?
Придётся расписывать/генерировать не только пользовательские классы, но и воплощения всех контейнеров/алгоритмов в которых они участвую — иначе тормоза.
Покажи какую-нибудь библиотеку/утилиту которая берёт всё это на себя.
Re[82]: Java vs C# vs C++
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 09.10.15 19:28
Оценка:
Здравствуйте, alex_public, Вы писали:

_>Здравствуйте, Serginio1, Вы писали:


_>>>Ох, ты похоже не понимаешь... Если переписать тот же 1C или скажем Питон с C++ на C#, то получившийся скриптовой язык станет только медленнее. Так понятно? )

S>> А зачем переписывать? Если можно сразу писать на C#? Мало того можно сравнить Питон на C++ и IronPython на C#

_>Затем, что все тормоза 1C следуют из этого. Но и основные преимущества (DSL) тоже происходят из этого же.

Из чего? Из-за того, что интерпритатор медленнее компилятора.

_>>>Ещё раз повторяю. Сравнение скорости 1C и C# — это бред.

S>> Зато сравнивать C# и С++ это нормально. У них разная ниша. Если на C# написать код аля 1С это не далеко от оригинала. Приблизительно как TS от JC
S>>то разница между 1С и С++ это уже разные миры.

_>C++ и C# — это оба языка общего назначения, а не DSL. Конечно их целевые ниши различаются, но на фоне разницы со скриптовыми языками это не принципиально.


_>И я очень сомневаюсь, что какие-то профильные задачи решаются похоже на C# и 1C. Озвучь задачи тогда уж... Может это не профильные задачи 1C, а что-то Обычное? ) Тогда оно и на C++ будет выглядеть тривиально.


Я тебе уже приводил Microsoft Dynamics CRM
_>>>Дело не только в этом, а ещё и в том, что 1C — это DSL. И соответственно в своей узкой области он в любом случае будет удобнее, чем любые универсальные языки.
S>> Я утвеждаю, что C# для решения подобных задач удобнее как TS vs JS. А я пишу на этих языках. Единственно, что нужно заменить англоязычные операторы на русские.

_>Сомнительно) Озвучь ка эти самые задачи...

Оооо ты не знаешь задачи 1С? Тогда сложно объяснять. На самом деле 1С и прочие системы имеют свой язык прежде всего, что бы на них зарабатывать. Когда они создавались C# был еще в так же как TS vs JS.
Как я тебе показывал ссылки есть некая иерархия классов Справочники,документы, регистры сведений,оборотов, остатков, Константы, Планы счетов итд
Я формирую аналогичные классы на C# только разумеется без модулей объектов.
Которые также можно написать. Некоторые люди даже переводят из одного языка в другой. https://infostart.ru/public/321282/
В свое время народ пытался сделать убийцу 1С.
и солнце б утром не вставало, когда бы не было меня
Re[82]: Java vs C# vs C++
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 09.10.15 19:28
Оценка:
Здравствуйте, alex_public, Вы писали:

_>Здравствуйте, Serginio1, Вы писали:


S>>>> Давай сравним с Microsoft Dynamics решающий аналогичную задачу

_>>>Если ты про Microsoft Dynamics ERP, то причём тут .net? )
S>>Например https://msdn.microsoft.com/en-us/library/hh547453.aspx

_>По ссылке у тебя Microsoft Dynamics CRM. Там да, .net, но какое отношение CRM имеет к 1C?

Это учетные системы.
и солнце б утром не вставало, когда бы не было меня
Re[82]: Java vs C# vs C++
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 09.10.15 19:32
Оценка:
Здравствуйте, alex_public, Вы писали:

_>Здравствуйте, Serginio1, Вы писали:


_>>>Ещё раз повторяю. Сравнение скорости 1C и C# — это бред.

S>>Казалось бы. Вот посмотри http://rsdn.ru/forum/dotnet/6185588.1
Автор: Serginio1
Дата: 17.09.15

S>>С помощью этого можно делать Сайт, Вэб сервисы на Asp.Net но никому это не нужно. 1С ник не знает .Net, а писатели Вэб приложения не знают структуру 1С.
S>>Поэтому проще написать вэб сервис на 1С, чем использовать быстрый доступ через Net.
S>>А ты говоришь скорость. Никому она не нужна. Ни одного комментария.

_>А где кто-то говорил, что в задачах 1C нужна скорость? )

Она нужна и очень. Пока ниша 1С это мелкий и средний бизнес. А для выхода на компании от 1000 пользователей скорости уже не хватает.
А там несколько и суммы другие. Прежде всего поддержка
и солнце б утром не вставало, когда бы не было меня
Re[28]: Java vs C# vs C++
От: · Великобритания  
Дата: 09.10.15 19:47
Оценка:
Здравствуйте, alex_public, Вы писали:

_>>>Т.е. ты считаешь, что ограничения виртуальной машины связаны исключительно с доступом к OS API? )

_>·>Я считаю, что ты фигню какую-то говоришь, что я перестал тебя понимать. Да, Джава не всемогутер, а хороший инструмент. Да, можно найти области, где этот инструмент не работает или работает плохо. Скажем, дравйвер видеокарты на Яве писать бессмысленно, если вообще возможно, а вот критичный LL код — вполне. Когда мы обсуждаем конкретные пункты, то можно уже сравнивать. Тут приводились какие-то пункты, по ним Джава, как выяснилось, не уступает и имеет некоторые преимущества.
_>Лично я знаю ровно одно преимущество Java/C#. Это возможность достаточно безопасного использования низкоквалифицированных программистов. Возможно с точки зрения технологии это звучит и не очень. Но с точки зрения бизнеса это очень существенное преимущество, правда актуальное в основном для не IT компаний. Так что благодаря этому преимуществу Java/C# заслуженно занимают доминирующее положение во внутрикорпоративном энтерпрайзе. И если их там кто-то и подвинет, то разве что JS, если обретёт соответствующую инфраструктуру (кстати шаги к этому уже наблюдаются). ))) А вот использование Java/C# в других областях, особенно со сложным кодом или тяжёлыми условиями, мне кажется неразумным. Но в нашей индустрии вообще много всего неразумного встречается. )))
Нет, это просто языки разного уровня. Ровно то же самое можно сказать заменив Java/C# -> C++, C++ -> ассемблер.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[34]: Java vs C# vs C++
От: · Великобритания  
Дата: 09.10.15 19:54
Оценка:
Здравствуйте, alex_public, Вы писали:

_>·>Затем что в Джаве эта проблема решена. Такого типа некорректный код — невозможен. Это является сильным преимуществом в некоторых ситуациях.

_>И в Java и в C++ будет одинаковый расклад для таких ситуаций — исключение (правда в C++ системное, а не родное).
_>
_>delete x;
x->>v=1;
_>

_>
_>x=null;
_>x.v=1;
_>

Неправда. Будет не исключение, а undefined behaviour, в дебаг-моде в лучшем случае может и грохнется. А если учесть всякие кастомные аллокаторы...
Помню натыкался на багу:
class X
{
   char *begin;
   char *end;
   int size() {return end - begin;}
}

Как думаешь что вернёт size() для удалённого объекта даже в дебаг моде?

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

EP>>>Это уберёт линейную сложность?

dot>>Да. Линейная сложность это худший случай, когда у тебя постоянно меняются указатели в большинтсве живых объектов и постоянно создаются новые.
EP>Не обязательно в большинстве живых, достаточно в относительно малом количестве.
Нет, поиск осуществляется по тронутым с предыдущего цикла сборки регионам объектов.

dot>>В такой ситуации С++ тоже не поздоровится — и фрагментация кучи, и возрастающая сложность malloc/free.

EP>Алгоритмическая сложность не "растёт" — это характеристика алгоритма. Например если брать Buddy — то она логарифмическая.
EP>Да, — чем больше N, тем будет дольше, но чтобы прикинуть как это "дольше" зависит от N — как раз и используют алгоритмическую сложность.
Хорошо, скорость падать, а не сложность расти.

dot>>>>Если ты в С++ заведёшь очередь для очистки — столкнёшься ровно с той же проблемой. Не вижу разницы.

EP>>>В очереди объекты которые уже готовы для очистки. А вот сколько там живых reachable объектов — не важно, пусть хоть десять миллиардов.
dot>>Ты представляешь как поплохеет системе когда туча тредов будет пихать миллиарды объекты в одну единственную очередь,
EP>Ещё раз, очередь у каждого потока своя, thread-local.
Если потоки не обмениваются объектами — это скучный случай, gc будет летать благодаря TLAB.

dot>>обрабатываемую одним несчастным потоком?

EP>Необязательно одним
А сколькими? И как будешь раздавать по потокам? Как contention разруливать?

dot>>>>И кто из этой очереди будет обрабатывать элементы? Сам thread — не может отвлекаться, он LL, в любую наносекунду может прийти новый запрос.

EP>>>От задачи зависит, может и сам thread. А может и отдельный thread, при этом contention с другими потоками всё равно не будет — так как очередь SPSC.
dot>>Мы вроде рассматриваем случай, когда sharedPtr.release может начаться из разных тредов. Как ты собираешься использовать single writer структуру?
EP>Объект управляемый shared_ptr всегда удаляется одним потоком, каким из них — определяется тем самым атомарным wait-free счётчиком. Это всё есть даже без отложенной очистки.
Я знаю что он удаляется одним потоком. Как сделать так, чтобы он не стал удаляться в критическом потоке?

dot>>>>Это тоже подзадача GC — решать сразу или отложить.

EP>>>А ещё в подзадачах GC есть сложение целых.
dot>>Хорошо, не подзадача, а средство достижения заявленных характеристик.
EP>Короче, не нужно сами эти средства называть GC. Другой пример — копирующий аллокатор может быть без GC.
Я говорю это к тому, что эти средства уже доступны при использовании GC.

EP>>>Каким образом ты реализуешь деструкторы? Какое будет использование? Каким образом реализуешь например Expression Templates и прочие compile-time EDSL?

dot>>А зачем compile time? Я знаю, что C++ compile time — Turing Complete, но в общем-то и в Java можно сделать плугин для компилятора или load-time кодогенерацию.
EP>Так фишка EDSL (Embedded Domain Specific Language) именно в том что он embedded.
Так он и будет Embedded, пишешь обычный код на java с аннотациями, а во время компиляции или загрузки классов — происходит магия.
Ну вот... рассуждали о управлении памятью, LL и внезапно слились до type system и EDSL.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[32]: Java vs C# vs C++
От: · Великобритания  
Дата: 09.10.15 20:30
Оценка:
Здравствуйте, alex_public, Вы писали:

_>>>·>А в плюсах ты явно будешь писать "vector<MyClass>()", "new vector<MyClass>()", "vector<MyClass*>()" или "new vector<MyClass*>()" — принимать это решение каждый раз на основе кучи предположений, умолчаний, ещё на стадии разработки архитектуры приложения, хотя в большинтсве случаев такие решения может принять JIT на основе знаний полученных на стадии исполнения кода у конечного пользователя.

_>>>Да, всё верно. И я уверен что во всех случаях сделаю это лучше чем JIT.
_>·>Про все случаи я уверен, что нет. Просто устанешь и начнёшь лепить что-то дефолтное, забивая на эффективность.
_>Фокус в том, что дефолтное в C++ как раз и есть самое быстрое для 99% задач. )
Это которое? Я ещё забыл варианты "MyClass[]", "MyClass*[]", все комбинации "xxx_ptr<vector<xxx_ptr<MyClass> >"

_>·>А как же абстракция и прочие умные слова? Вместо простого "список объектов" начинаешь рассуждать как же оно будет в памяти, куча, стек, индирекции, индексы, указатели... И это чуть ли не для каждой строчки кода, а не для того 1% строчек где это действительно важно.

_>А что, разве не все программисты такое обдумывают на автомате в процессе проектирования?
А ты часто обдумываешь в какие регистры процессора какая переменная попадёт?
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[36]: Java vs C# vs C++
От: · Великобритания  
Дата: 09.10.15 20:46
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

dot>>ну например List<MyObj>

EP>1. На GC всё равно будет висеть граф множества объектов, пусть и меньшего размера.
Ничего, и не такое жевал.

EP>2. Теперь на этих ссылках будут висеть финализаторы, так? Для того чтобы знать когда очищать off-heap. То есть теперь ко всему прочему ещё и освобождение будет линейным.

Можно и финализаторы, а можно и явно реализовать delete, как в плюсах. Какое освобождение сделаешь, такое и будет.

EP>3. Лишние индерекции внутри List никуда не делись.

List будет с большим числом элементов, иначе смысла извращаться нет. А на фоне этого большого числа данных один индирект не будет заметен в микроскоп.

EP>>>И кто и как создаст эти newMyObj?

dot>>Программист напишет. Притом можно описывать, скажем, интерфейсы, а их имплементации генерить при запуске.
EP>"в общем-то и вся разница по факту." — да?
EP>Придётся расписывать/генерировать не только пользовательские классы, но и воплощения всех контейнеров/алгоритмов в которых они участвую — иначе тормоза.
EP>Покажи какую-нибудь библиотеку/утилиту которая берёт всё это на себя.
Берёт что? Код-то тривиальный.
Вместо
class BusinessData
{
  private int a;
  private int b;
  int getA() {return a}
  int getB() {return b}
}

пишем
class BusinessData
{
  private Buffer buf;//замаплен например сразу на приходящий из сети блок байт или offheap хранилище или ещё чего.
  private int pos;
  int getA() {return buf.getInt(pos)}
  int getB() {return buf.getInt(pos+4)}
}

List<> просто проставляет pos соответственно.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[33]: Java vs C# vs C++
От: Evgeny.Panasyuk Россия  
Дата: 09.10.15 20:51
Оценка:
Здравствуйте, ·, Вы писали:

EP>>>>Это уберёт линейную сложность?

dot>>>Да. Линейная сложность это худший случай, когда у тебя постоянно меняются указатели в большинтсве живых объектов и постоянно создаются новые.
EP>>Не обязательно в большинстве живых, достаточно в относительно малом количестве.
dot>Нет, поиск осуществляется по тронутым с предыдущего цикла сборки регионам объектов.

Об этом и речь — что по регионам, а не отдельным затронутым объектам. Поэтому я и сказал "малом количестве", а не в одном.
И то — это отслеживание имеет свою цену, которая размазывается по всему коду.

dot>>>В такой ситуации С++ тоже не поздоровится — и фрагментация кучи, и возрастающая сложность malloc/free.

EP>>Алгоритмическая сложность не "растёт" — это характеристика алгоритма. Например если брать Buddy — то она логарифмическая.
EP>>Да, — чем больше N, тем будет дольше, но чтобы прикинуть как это "дольше" зависит от N — как раз и используют алгоритмическую сложность.
dot>Хорошо, скорость падать, а не сложность расти.

При логарифмической сложности между N=1000 и N=1000000 — разница примерно в два раза. А в случае же линейной сложности — примерно в тысячу раз
Feel the paindifference.

dot>>>>>Если ты в С++ заведёшь очередь для очистки — столкнёшься ровно с той же проблемой. Не вижу разницы.

EP>>>>В очереди объекты которые уже готовы для очистки. А вот сколько там живых reachable объектов — не важно, пусть хоть десять миллиардов.
dot>>>Ты представляешь как поплохеет системе когда туча тредов будет пихать миллиарды объекты в одну единственную очередь,
EP>>Ещё раз, очередь у каждого потока своя, thread-local.
dot>Если потоки не обмениваются объектами — это скучный случай,

А зачем обмениваться практически мёртвыми объектами?

dot>>>обрабатываемую одним несчастным потоком?

EP>>Необязательно одним
dot>А сколькими? И как будешь раздавать по потокам? Как contention разруливать?

Так зависит от задачи — где-то просто достаточно thread pool. Где-то же будет один очищатель на один рабочий поток и т.п. И то, это только если такая проблема вообще возникнет.
Но это всё уже не важно — главное разгрузить рабочий поток

dot>>>>>И кто из этой очереди будет обрабатывать элементы? Сам thread — не может отвлекаться, он LL, в любую наносекунду может прийти новый запрос.

EP>>>>От задачи зависит, может и сам thread. А может и отдельный thread, при этом contention с другими потоками всё равно не будет — так как очередь SPSC.
dot>>>Мы вроде рассматриваем случай, когда sharedPtr.release может начаться из разных тредов. Как ты собираешься использовать single writer структуру?
EP>>Объект управляемый shared_ptr всегда удаляется одним потоком, каким из них — определяется тем самым атомарным wait-free счётчиком. Это всё есть даже без отложенной очистки.
dot>Я знаю что он удаляется одним потоком. Как сделать так, чтобы он не стал удаляться в критическом потоке?

Критический поток поставит его в очередь, а сам удалять не будет.

dot>>>>>Это тоже подзадача GC — решать сразу или отложить.

EP>>>>А ещё в подзадачах GC есть сложение целых.
dot>>>Хорошо, не подзадача, а средство достижения заявленных характеристик.
EP>>Короче, не нужно сами эти средства называть GC. Другой пример — копирующий аллокатор может быть без GC.
dot>Я говорю это к тому, что эти средства уже доступны при использовании GC.

Аналогия: "когда нарезаешь массив на структуру, переизобретаешь C++"

EP>>>>Каким образом ты реализуешь деструкторы? Какое будет использование? Каким образом реализуешь например Expression Templates и прочие compile-time EDSL?

dot>>>А зачем compile time? Я знаю, что C++ compile time — Turing Complete, но в общем-то и в Java можно сделать плугин для компилятора или load-time кодогенерацию.
EP>>Так фишка EDSL (Embedded Domain Specific Language) именно в том что он embedded.
dot>Так он и будет Embedded, пишешь обычный код на java с аннотациями, а во время компиляции или загрузки классов — происходит магия.

Как сделаешь например элементарный анализ размерностей? Чтобы вот такое выражение выдавало ошибку на этапе компиляции 20m/3s + 2kg?

dot>Ну вот... рассуждали о управлении памятью, LL и внезапно слились до type system и EDSL.


Так это ты же "внезапно" кидаешься громкими заявлениями "и прочие С++ фишки можно реализовать в java"
Re[37]: Java vs C# vs C++
От: Evgeny.Panasyuk Россия  
Дата: 09.10.15 21:06
Оценка:
Здравствуйте, ·, Вы писали:

dot>>>ну например List<MyObj>

EP>>1. На GC всё равно будет висеть граф множества объектов, пусть и меньшего размера.
dot>Ничего, и не такое жевал.

Так в off-heap тогда смысла мало

EP>>2. Теперь на этих ссылках будут висеть финализаторы, так? Для того чтобы знать когда очищать off-heap. То есть теперь ко всему прочему ещё и освобождение будет линейным.

dot>Можно и финализаторы, а можно и явно реализовать delete, как в плюсах. Какое освобождение сделаешь, такое и будет.

В итоге получаем и линейный обход живых, и линейных обход мёртвых, да ещё и второй аллокатор/деаллокатор (кстати какой?), и в довесок ещё расстрел памяти.
Круто — чё

EP>>3. Лишние индерекции внутри List никуда не делись.

dot>List будет с большим числом элементов, иначе смысла извращаться нет. А на фоне этого большого числа данных один индирект не будет заметен в микроскоп.

Это один индерект на каждый элемент, а не просто один индерект. Разница может быть на порядки

EP>>>>И кто и как создаст эти newMyObj?

dot>>>Программист напишет. Притом можно описывать, скажем, интерфейсы, а их имплементации генерить при запуске.
EP>>"в общем-то и вся разница по факту." — да?
EP>>Придётся расписывать/генерировать не только пользовательские классы, но и воплощения всех контейнеров/алгоритмов в которых они участвую — иначе тормоза.
EP>>Покажи какую-нибудь библиотеку/утилиту которая берёт всё это на себя.
dot>Берёт что? Код-то тривиальный.

Берёт описание структур и генерирует все необходимые комбинации класс-контейнер/алгоритм.

dot>Вместо

dot>
dot>class BusinessData
dot>{
dot>  private int a;
dot>  private int b;
dot>  int getA() {return a}
dot>  int getB() {return b}
dot>}
dot>


Тут вообще достаточно:
struct BusinessData
{
    int a, b;
};

Зачем get/set?

dot>пишем


Та самая ручная нарезка на структуры:

dot>
dot>class BusinessData
dot>{
dot>  private Buffer buf;//замаплен например сразу на приходящий из сети блок байт или offheap хранилище или ещё чего.
dot>  private int pos;
dot>  int getA() {return buf.getInt(pos)}
dot>  int getB() {return buf.getInt(pos+4)}
dot>}
dot>


Так это же не спасает от тех же лишних индерекций которые есть в List<BusinessData>
Отредактировано 09.10.2015 21:10 Evgeny.Panasyuk . Предыдущая версия .
Re[30]: Java vs C# vs C++
От: · Великобритания  
Дата: 09.10.15 21:08
Оценка:
Здравствуйте, alex_public, Вы писали:

_>>>Я ничего подобного не упоминал, т.к. это совсем не моя область. Да, и кстати, насколько я понял данные продукты упоминались в том контексте, что мол посмотрите как надо извратить Java, чтобы была возможность конкурировать в данной области.

_>·>Вот возьми что-нибудь из http://codedependents.com/2014/01/27/11-best-practices-for-low-latency-systems/ и подумай что именно тут java-specific? Все те же извраты будут и в плюсах.
_>Ну если смотреть на этот список с точки зрения C++, то там вообще нет никаких извращений. Вполне нормальные архитектурные элементы не приводящие ни к каким ужасам.
"Извращения" это непривычный код, не так как учат в букварях.
Почитай, кстати там комменты — о том же рассуждают. Хорошо сказано:

Java is a great platform none the less, but I think it’s biggest advantage is that ordinary business logic (90% of your code?) can still depend on GC and safety features and make use of highly tuned and tested libraries written with Unsafe. This is a great trade-off between getting the last 5% of perf and being productive. A trade-off that makes sense for a lot of people but a trade-off none the less. Writing complicated application code in C/C++ is a nightmare after all.


_>Если же взглянуть с точки зрения Java, то один пункт действительно становится извратом, реализация которого будет требовать страшного кода. Это пункт "Keep your reads sequential". Кстати как раз это мы обсуждали в соседнем сообщение.

И это ВНЕЗАПНО нужно делать и в плюсах, банальный vector<MyClass> может работать плохо, если, например, в классе куча полей, а тебя нужно последовательно читать только одно, вылезет structure of arrays и т.п.


_>Из опыта каких компаний?

Упомянутых в топике.

_>Где java системы реалтаймого видео? )

"«Ага!!!» — укоризненно сказали суровые сибирские плюсовики!"
даже не знаю что на такое возразить.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[34]: Java vs C# vs C++
От: · Великобритания  
Дата: 09.10.15 21:38
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>>>Не обязательно в большинстве живых, достаточно в относительно малом количестве.

dot>>Нет, поиск осуществляется по тронутым с предыдущего цикла сборки регионам объектов.
EP>Об этом и речь — что по регионам, а не отдельным затронутым объектам. Поэтому я и сказал "малом количестве", а не в одном.
EP>И то — это отслеживание имеет свою цену, которая размазывается по всему коду.
Я уже упоминал, что gc плохо работает в случае большого числа короткоживущих и толпы долгоживущих. При наличии среднеживущих — производительность падает. Это можно лечить настройкой GC, испоьзованием разных приёмов (flyweight или пулов например) или даже изменением архитектуры приложения.

dot>>>>В такой ситуации С++ тоже не поздоровится — и фрагментация кучи, и возрастающая сложность malloc/free.

EP>>>Алгоритмическая сложность не "растёт" — это характеристика алгоритма. Например если брать Buddy — то она логарифмическая.
EP>>>Да, — чем больше N, тем будет дольше, но чтобы прикинуть как это "дольше" зависит от N — как раз и используют алгоритмическую сложность.
dot>>Хорошо, скорость падать, а не сложность расти.
EP>При логарифмической сложности между N=1000 и N=1000000 — разница примерно в два раза. А в случае же линейной сложности — примерно в тысячу раз
EP>Feel the paindifference.
Бывает. Лечится. Алгоритмы — сила.

dot>>>>Ты представляешь как поплохеет системе когда туча тредов будет пихать миллиарды объекты в одну единственную очередь,

EP>>>Ещё раз, очередь у каждого потока своя, thread-local.
dot>>Если потоки не обмениваются объектами — это скучный случай,
EP>А зачем обмениваться практически мёртвыми объектами?
В смысле? Какие уж есть.

dot>>>>обрабатываемую одним несчастным потоком?

EP>>>Необязательно одним
dot>>А сколькими? И как будешь раздавать по потокам? Как contention разруливать?
EP>Так зависит от задачи — где-то просто достаточно thread pool. Где-то же будет один очищатель на один рабочий поток и т.п. И то, это только если такая проблема вообще возникнет.
EP>Но это всё уже не важно — главное разгрузить рабочий поток
Ну собственно и получается — gc солнца вручную. Понятно, что gc можно реализовать на С++, он и реализован на С++ в JVM.

EP>>>>>От задачи зависит, может и сам thread. А может и отдельный thread, при этом contention с другими потоками всё равно не будет — так как очередь SPSC.

dot>>>>Мы вроде рассматриваем случай, когда sharedPtr.release может начаться из разных тредов. Как ты собираешься использовать single writer структуру?
EP>>>Объект управляемый shared_ptr всегда удаляется одним потоком, каким из них — определяется тем самым атомарным wait-free счётчиком. Это всё есть даже без отложенной очистки.
dot>>Я знаю что он удаляется одним потоком. Как сделать так, чтобы он не стал удаляться в критическом потоке?
EP>Критический поток поставит его в очередь, а сам удалять не будет.
И возникнет та же проблема, которой ты меня мучил — а что если он будет ставить в очередь быстрее, чем эта очередь разгребаться?

EP>>>>>А ещё в подзадачах GC есть сложение целых.

dot>>>>Хорошо, не подзадача, а средство достижения заявленных характеристик.
EP>>>Короче, не нужно сами эти средства называть GC. Другой пример — копирующий аллокатор может быть без GC.
dot>>Я говорю это к тому, что эти средства уже доступны при использовании GC.
EP>Аналогия: "когда нарезаешь массив на структуру, переизобретаешь C++"
Не С++. Почему именно С++, а не С, не Алгол, не Фортран, не Паскаль, не ассемблер? Просто подгоняешь код к специфике железа.

EP>>>Так фишка EDSL (Embedded Domain Specific Language) именно в том что он embedded.

dot>>Так он и будет Embedded, пишешь обычный код на java с аннотациями, а во время компиляции или загрузки классов — происходит магия.
EP>Как сделаешь например элементарный анализ размерностей? Чтобы вот такое выражение выдавало ошибку на этапе компиляции 20m/3s + 2kg?
http://types.cs.washington.edu/checker-framework/current/checker-framework-manual.html#units-checker

dot>>Ну вот... рассуждали о управлении памятью, LL и внезапно слились до type system и EDSL.

EP>Так это ты же "внезапно" кидаешься громкими заявлениями "и прочие С++ фишки можно реализовать в java"
Так можно же, turing complete же. Нужно ли — вопрос.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[35]: Java vs C# vs C++
От: Evgeny.Panasyuk Россия  
Дата: 09.10.15 22:12
Оценка:
Здравствуйте, ·, Вы писали:

EP>>>>Не обязательно в большинстве живых, достаточно в относительно малом количестве.

dot>>>Нет, поиск осуществляется по тронутым с предыдущего цикла сборки регионам объектов.
EP>>Об этом и речь — что по регионам, а не отдельным затронутым объектам. Поэтому я и сказал "малом количестве", а не в одном.
EP>>И то — это отслеживание имеет свою цену, которая размазывается по всему коду.
dot>Я уже упоминал, что gc плохо работает в случае большого числа короткоживущих и толпы долгоживущих. При наличии среднеживущих — производительность падает.

А как ты называешь объекты которые живут долго, но не до конца работы приложения?

dot>Это можно лечить настройкой GC, испоьзованием разных приёмов (flyweight или пулов например)


Причём тут flyweight? Объекты-то изменяются.

dot>или даже изменением архитектуры приложения.


Конечно, поэтому и появляются всякие GC-free и off-heap'ы

dot>>>>>В такой ситуации С++ тоже не поздоровится — и фрагментация кучи, и возрастающая сложность malloc/free.

EP>>>>Алгоритмическая сложность не "растёт" — это характеристика алгоритма. Например если брать Buddy — то она логарифмическая.
EP>>>>Да, — чем больше N, тем будет дольше, но чтобы прикинуть как это "дольше" зависит от N — как раз и используют алгоритмическую сложность.
dot>>>Хорошо, скорость падать, а не сложность расти.
EP>>При логарифмической сложности между N=1000 и N=1000000 — разница примерно в два раза. А в случае же линейной сложности — примерно в тысячу раз
EP>>Feel the paindifference.
dot>Бывает. Лечится. Алгоритмы — сила.

Конечно сила, о чём я тебе и говорю.
И при логарифмической сложности, и при линейной, чем больше N тем медленнее — но разница между ними колоссальная. И в результате ситуации совершенно разные, а ты говоришь "тоже не поздоровится"

dot>>>>>Ты представляешь как поплохеет системе когда туча тредов будет пихать миллиарды объекты в одну единственную очередь,

EP>>>>Ещё раз, очередь у каждого потока своя, thread-local.
dot>>>Если потоки не обмениваются объектами — это скучный случай,
EP>>А зачем обмениваться практически мёртвыми объектами?
dot>В смысле? Какие уж есть.

Контекст потерял? Ещё раз.
У нас есть объект, счётчик ссылок которого ушёл в ноль. Так? Зачем обмениваться им с другими рабочими потоками?

EP>>Критический поток поставит его в очередь, а сам удалять не будет.

dot>И возникнет та же проблема, которой ты меня мучил — а что если он будет ставить в очередь быстрее, чем эта очередь разгребаться?

Проблема вообще-то была в другом. Если по аналогии — в том что грубо говоря pop одного элемента очереди линейно зависит от её размера. Здесь же такой зависимости нет.

EP>>>>>>А ещё в подзадачах GC есть сложение целых.

dot>>>>>Хорошо, не подзадача, а средство достижения заявленных характеристик.
EP>>>>Короче, не нужно сами эти средства называть GC. Другой пример — копирующий аллокатор может быть без GC.
dot>>>Я говорю это к тому, что эти средства уже доступны при использовании GC.
EP>>Аналогия: "когда нарезаешь массив на структуру, переизобретаешь C++"
dot>Не С++. Почему именно С++, а не С, не Алгол, не Фортран, не Паскаль, не ассемблер?

Аналогично — а почему тогда GC?

EP>>>>Так фишка EDSL (Embedded Domain Specific Language) именно в том что он embedded.

dot>>>Так он и будет Embedded, пишешь обычный код на java с аннотациями, а во время компиляции или загрузки классов — происходит магия.
EP>>Как сделаешь например элементарный анализ размерностей? Чтобы вот такое выражение выдавало ошибку на этапе компиляции 20m/3s + 2kg?
dot>http://types.cs.washington.edu/checker-framework/current/checker-framework-manual.html#units-checker

Какой объем реализации? На C++ — меньше ста строк.
Да и не сравнится ведь:
@m int meters = 5 * UnitsTools.m;

vs
auto length = 5m;

Да и нет интеграции в систему типов — например перегрузка не работает

dot>>>Ну вот... рассуждали о управлении памятью, LL и внезапно слились до type system и EDSL.

EP>>Так это ты же "внезапно" кидаешься громкими заявлениями "и прочие С++ фишки можно реализовать в java"
dot>Так можно же, turing complete же. Нужно ли — вопрос.

Полнота по Тьюрингу вообще о другом — о тех программах которые можно реализовать. Разговор же про языковые фичи, с помощью которых происходит реализация
Re[26]: Java vs C# vs C++
От: · Великобритания  
Дата: 09.10.15 22:33
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

dot>>>>Перенос объекта на стек это другая оптимизация. Может делаться только для маленьких оъбектов. Если у тебя выделяется 100мб массив и EA покажет, что ссылка на массив не убегает за пределы, то при выходе из стека объект грохнется. Т.е. по сути тот же unique_ptr.

EP>>>То есть имелось в виду scoped_ptr — более ограниченная версия unique_ptr. Например unique_ptr можно возвращать из функции.
dot>>EA работает и с множеством функций. Сделай "byte[] func() {return new byte[100500];}"- ничего страшного.
EP>Ближе, но всё равно не то — unique_ptr можно передавать хоть вверх, хоть вниз, хоть сохранить в массиве, и это всё работает даже без инлайнинга.
EP>Да даже в одном scope EA далеко не всегда сможет доказать что нет escape — банально упрётся в halting problem.
Не сможет — чуть тормозить начнёт. А если человек не сможет доказать передачу указателей — всё круто и непредсказуемо навернётся.

dot>>>>И молись что N не слишком большой и не получится stack overflow на пустом месте.

_>>>Вектор не выделяет память на стеке. Ну во всяком случае со стандартным аллокатором. ))) Ты уверен, что ты реально знаком с C++? )
dot>>Ах, да, не заметил. Да ты меня запутал. Говорил о размещении объектов на стеке, и внезапно опять куча.
EP>Да нет никакого запутывания. Если бы ты знал язык, без всякого углубления в advanced фичи — ты бы никогда не запутался.
Да знаю я язык прекрасно, опыта 5+ лет, просто уже несколько лет не использовал на работе.

EP>Это типичный миф обитающий в среде Java/C# — мол на каждый наш new, будет какой-нибудь *_ptr в C++.

... либо битый указатель.

EP>Этот феномен даже Страуструп высмеивал — https://youtu.be/OB-bdWKwXsU?t=1984

EP>Причём по сути это относится не только к *_ptr — а и в общем очень много мифов относительно C++. И в общем не так страшен чёртC++, как его малюют.
Вот и говорит, что нужен протокол для каждого объекта, решать кто что делает с объектами.
Тут ведь как:
было
void showDialog()
{
  Widget g;
  ...
  doer.doSomething(g);
  ...
}

//и вдруг мы решили поменять имплементацию doSomething чтобы что-то делалось в другом треде, и мы знаем, что он завершится до закрытия диалога. А потом вдруг тред стормозил или появился другой способ закрытия диалога...

dot>>>>массив не убегает за пределы, то при выходе из стека объект грохнется

EP>>>Каким образом грохнется? Речь только про некомпактифицируемые кучи?
dot>>Самое тривиальное — копирующим GC.

EP>Каким образом? Положили в память эти non-escape данные, дальше вызвали какую-нибудь стороннюю функцию (не давая ей наши non-escape) — она сделала дальше какие-то аллокации, которые пошли следом за нашими non-escape данным.

EP>Выходим из scope — дальше какие действия? Какое преимущество даст EA в этом случае?
Тем что объект пойдёт на стек или в регистры. Какие аллокации?

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

EP>>>>>Smart-pointer'ы прежде всего помогают избавиться от голых владеющих указателей, а не от того что ты подумал.
dot>>>>Бррр... Я уж надеялся, что голые указатели постепенно изничтожаются.
EP>>>Ты что, они же есть в реальности данной нам в ощущениях железом. Это же например самый быстрый способ указать на конкретный элемент массива, или передать куда-нибудь его часть.
dot>>Железом нам даны адреса, а не указатели.
EP>А указатель что по-твоему хранит?
Указатель ещё тип имеет. Ссылка в яве тоже адрес хранит и чё.

dot>>>>Это же сценарий high throughput, а не low latency. В такой ситуации и C++ грохнется — он будет делать ту же работу, просто в рабочих тредах, а на в отдельных gc-тредах как java.

EP>>>Не грохнется — у него нет зависимости O(N) от количества живых объектов.
dot>>new/malloc и delete/free работают не за O(1) внезапно.
EP>Например для Buddy Allocation сложность логарифмическая. Есть же в том числе и O(1) алгоритмы, например TLSF.
Так и разные алгоритмы GC есть. И столько всего можно крутить... И я уверен, что вариантов даже больше, ибо ссылка в jvm более абстрактна чем указатели в плюсах, а значит больше простора для оптимизаций.


dot>>Как известно, gc работает хорошо при короткоживущих и длинноживущих объектах.

EP>То есть при любых?
Нет, среднеживущие ещё есть.

dot>>Quick-sort имеет сложность O(N*N), как и пузырьковая... но это ещё ничего не значит.

EP>Конечно значит, именно поэтому в реализациях std::sort используется introsort, которая хоть и основана на quicksort, но выдаёт линеаритмическую сложность
Да, неудачный пример. Лучше рассмотреть hashtable. Сложность O(n). и что? Просто крутят использование до тех пор пока не станет почти O(1). Примерно так и с GC.

EP>>>Ты постоянно говоришь о каком-то одном use-case'ы.

EP>>>Даже если и мало — всё равно придётся опускаться на очень низкий уровень, исключительно из-за самого языка.
dot>>Я и не изобретаю общую теорию всего, а решаю практические задачи.
EP>А кто-то изобретает? В Java нет структур — это практический недостаток и факт
Зато он даёт больший простор для JVM/JIT/etc.
Ну вот есть структуры в C# — а толку? Где LL?

EP>>>Это ты о чём?

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

dot>>Если ты про ссылочное дерево — то уже всё плохо, ибо оно не будет в памяти последовательно.

EP>Деревья используются на практике. Хранение данных в самом узле позволяет избавится от лишней индерекции.
Это какие-то очень экзотические условия, у меня не получается представить когда в ссылочном дереве лишняя индирекция может стать серьёзной проблемой.

dot>>>>В C++ можно тоже кучу главных причин тормозов придумать. Скажем, передача by-value. Непонятно только к чему это.

EP>>>Так тут есть простой выбор — by-value или by-reference. Это совершенно не тоже самое что и засучив рукава нарезать байт-буфера на структуры
dot>>by-value — и тут ВНЕЗАПНО появляется O(N) от числа живых объектов.
EP>Далеко не всегда. Да и почему внезапно-то?
Настолько же ВНЕЗАПНО как и в случае с GC.

dot>>by-reference — и тут начинаются проблемы с временем жизни, засучив рукава начинаешь решать проблемы владения.

EP>В 99.999% случаях ничего "засучивать" не нужно, и никакие *_ptr не нужны.
Так в этих же случаях и в яве всё будет всё в YG, а значит никакого жуткого O(N).

dot>>Зато гарантируется отсутствие битых ссыслок.

EP>Да, это плюс — с этим никто не спорил
Притом очень ценный плюс, что он перевешивает весь колбасокод с оффхипами и т.д.

EP>>>Да, на C++ нужно думать/помнить о владении (это не означает что каждый new на Java превращается в *_ptr).

EP>>>Нет, уровни абстракции о которых я говорю решают далеко не только проблемы владения — они позволяют писать высокоуровневый И быстрый код.
dot>>Это мы переходим в другую плоскость — выразительность языка, а не собственно JVM/GC. Для JVM есть и другие языки — Scala, Ceylon, Kotlin и прочее, которые позволяют и многие твои любимые абстракции.
EP>А мы ВНЕЗАПНО не JVM обсуждаем, а вполне конкретную Java. Если брать JVM — то например если в неё скомпилировать C++ — то он там положит всех на лопатки
Не положит, к сожалению. Иначе бы уже давно компилировали.
Вся эта указательная магия и арифметика, юнионы, и прочий low level не может быть покрыт GC и JVM ссылками, поэтому при компиляции С/C++ память будет внутри byte[].

dot>>и прочее, которые позволяют и многие твои любимые абстракции

EP>Я говорю не просто про абстракции, а про бесплатные, либо крайне дешёвые.
Ценой других абстракций.

dot>>Выразительность языка с другой стороны стреляет отстутсвием нормальной IDE.


EP>Это тоже передёргивание.

EP>Нормальные IDE есть. Да автоматический анализ кода сложнее, но сложнее не из-за выразительности, а из-за внутренних особенностей сложившихся исторически. Языку больше тридцати лет, а если брать с базу C (из которой многие недостатки и произрастают) — то больше сорока.
EP>При этом аналогичную выразительность можно достичь не делая проблемы анализаторам.
Может и можно... Я сходу не могу сделать такое заявление.

EP>Те же структуры есть в C#.

А толку-то от них...
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[38]: Java vs C# vs C++
От: · Великобритания  
Дата: 09.10.15 22:50
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

dot>>>>ну например List<MyObj>

EP>>>1. На GC всё равно будет висеть граф множества объектов, пусть и меньшего размера.
dot>>Ничего, и не такое жевал.
EP>Так в off-heap тогда смысла мало
Когда как. Очень зависит от юзкейсов. Невозможно сказать: "делай так и будет быстро".

EP>>>2. Теперь на этих ссылках будут висеть финализаторы, так? Для того чтобы знать когда очищать off-heap. То есть теперь ко всему прочему ещё и освобождение будет линейным.

dot>>Можно и финализаторы, а можно и явно реализовать delete, как в плюсах. Какое освобождение сделаешь, такое и будет.
EP>В итоге получаем и линейный обход живых, и линейных обход мёртвых, да ещё и второй аллокатор/деаллокатор (кстати какой?), и в довесок ещё расстрел памяти.
EP>Круто — чё
Если очень надо и до машкодов дойдёшь. Но это очень экзотические случаи.

EP>>>3. Лишние индерекции внутри List никуда не делись.

dot>>List будет с большим числом элементов, иначе смысла извращаться нет. А на фоне этого большого числа данных один индирект не будет заметен в микроскоп.
EP>Это один индерект на каждый элемент, а не просто один индерект. Разница может быть на порядки

dot>>
dot>>class BusinessData
dot>>{
dot>>  private Buffer buf;//замаплен например сразу на приходящий из сети блок байт или offheap хранилище или ещё чего.
dot>>  private int pos;
dot>>  int getA() {return buf.getInt(pos)}
dot>>  int getB() {return buf.getInt(pos+4)}
dot>>}
dot>>


EP>Так это же не спасает от тех же лишних индерекций которые есть в List<BusinessData>

Двигаешь pos и получаешь элемент. Притом чтобы это всё имело смысл — pos должен двигаться строго вперёд, до следующего элемента, это и будет оптимизация sequencial access, а какие всякие другие алгоритмы ты тут хочешь воротить?
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[36]: Java vs C# vs C++
От: · Великобритания  
Дата: 09.10.15 23:12
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>>>Об этом и речь — что по регионам, а не отдельным затронутым объектам. Поэтому я и сказал "малом количестве", а не в одном.

EP>>>И то — это отслеживание имеет свою цену, которая размазывается по всему коду.
dot>>Я уже упоминал, что gc плохо работает в случае большого числа короткоживущих и толпы долгоживущих. При наличии среднеживущих — производительность падает.
EP>А как ты называешь объекты которые живут долго, но не до конца работы приложения?
Old Gen. Данные этих объектов можно менять свободно, но не трогать сильно указатели.

dot>>Это можно лечить настройкой GC, испоьзованием разных приёмов (flyweight или пулов например)

EP>Причём тут flyweight? Объекты-то изменяются.
Смотря как изменяются.

dot>>или даже изменением архитектуры приложения.

EP>Конечно, поэтому и появляются всякие GC-free и off-heap'ы
Пусть появляются там где действительно надо.

EP>>>При логарифмической сложности между N=1000 и N=1000000 — разница примерно в два раза. А в случае же линейной сложности — примерно в тысячу раз

EP>>>Feel the paindifference.
dot>>Бывает. Лечится. Алгоритмы — сила.
EP>Конечно сила, о чём я тебе и говорю.
EP>И при логарифмической сложности, и при линейной, чем больше N тем медленнее — но разница между ними колоссальная. И в результате ситуации совершенно разные, а ты говоришь "тоже не поздоровится"
Так вот строгость ссылок явы позволяет применять гораздо более хитрые алгоритмы.

EP>>>А зачем обмениваться практически мёртвыми объектами?

dot>>В смысле? Какие уж есть.
EP>Контекст потерял? Ещё раз.
EP>У нас есть объект, счётчик ссылок которого ушёл в ноль. Так? Зачем обмениваться им с другими рабочими потоками?
Так ты не знаешь в каком именно потоке и когда он уйдёт в ноль и что именно произойдёт в момент ухода в ноль. В этом и суть GC. Да, узнать можно, но это очень трудоёмко. Компьютер с этим справляется в подавляющем большинстве случаев лучше и надёжнее.

EP>>>Критический поток поставит его в очередь, а сам удалять не будет.

dot>>И возникнет та же проблема, которой ты меня мучил — а что если он будет ставить в очередь быстрее, чем эта очередь разгребаться?
EP>Проблема вообще-то была в другом. Если по аналогии — в том что грубо говоря pop одного элемента очереди линейно зависит от её размера. Здесь же такой зависимости нет.
Не одного элемента, а всей очереди. GC за цикл собирает не один объект.

dot>>>>>>Хорошо, не подзадача, а средство достижения заявленных характеристик.

EP>>>>>Короче, не нужно сами эти средства называть GC. Другой пример — копирующий аллокатор может быть без GC.
dot>>>>Я говорю это к тому, что эти средства уже доступны при использовании GC.
EP>>>Аналогия: "когда нарезаешь массив на структуру, переизобретаешь C++"
dot>>Не С++. Почему именно С++, а не С, не Алгол, не Фортран, не Паскаль, не ассемблер?
EP>Аналогично — а почему тогда GC?
Потому что управление памятью — трудоёмкий процесс в прикладных приложениях. Автоматизировать его — дело святое.

EP>Какой объем реализации? На C++ — меньше ста строк.

Ну вот... сейчас ещё начнём строки считать... увольте.

EP>Да и не сравнится ведь:

EP>
EP>@m int meters = 5 * UnitsTools.m;
EP>

EP>vs
EP>
EP>auto length = 5m;
EP>

EP>Да и нет интеграции в систему типов — например перегрузка не работает
Перегрузка чего? Это же примитивы.
И вообще, чего опять о языке, мы же о GC вроде? Ну возьми Скалу, там есть перегрузка.

dot>>>>Ну вот... рассуждали о управлении памятью, LL и внезапно слились до type system и EDSL.

EP>>>Так это ты же "внезапно" кидаешься громкими заявлениями "и прочие С++ фишки можно реализовать в java"
dot>>Так можно же, turing complete же. Нужно ли — вопрос.
EP>Полнота по Тьюрингу вообще о другом — о тех программах которые можно реализовать. Разговор же про языковые фичи, с помощью которых происходит реализация
GC это не совсем языковая фича. Возьми Скалу, если так нужны фичи.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[27]: Java vs C# vs C++
От: Evgeny.Panasyuk Россия  
Дата: 10.10.15 00:01
Оценка:
Здравствуйте, ·, Вы писали:

dot>>>>>Перенос объекта на стек это другая оптимизация. Может делаться только для маленьких оъбектов. Если у тебя выделяется 100мб массив и EA покажет, что ссылка на массив не убегает за пределы, то при выходе из стека объект грохнется. Т.е. по сути тот же unique_ptr.

EP>>>>То есть имелось в виду scoped_ptr — более ограниченная версия unique_ptr. Например unique_ptr можно возвращать из функции.
dot>>>EA работает и с множеством функций. Сделай "byte[] func() {return new byte[100500];}"- ничего страшного.
EP>>Ближе, но всё равно не то — unique_ptr можно передавать хоть вверх, хоть вниз, хоть сохранить в массиве, и это всё работает даже без инлайнинга.
EP>>Да даже в одном scope EA далеко не всегда сможет доказать что нет escape — банально упрётся в halting problem.
dot>Не сможет — чуть тормозить начнёт. А если человек не сможет доказать передачу указателей — всё круто и непредсказуемо навернётся.

А зачем человеку доказывать? Например:
auto foo()
{
    return calc(make_unique<Something>());
}
Результат может содержать ссылку на этот unique, а может не содержать. Человек может например просто знать из документации что в результирующем объекте нет этого unique. Анализатору же придётся это доказывать проинлайнив весь код.

dot>>>>>И молись что N не слишком большой и не получится stack overflow на пустом месте.

_>>>>Вектор не выделяет память на стеке. Ну во всяком случае со стандартным аллокатором. ))) Ты уверен, что ты реально знаком с C++? )
dot>>>Ах, да, не заметил. Да ты меня запутал. Говорил о размещении объектов на стеке, и внезапно опять куча.
EP>>Да нет никакого запутывания. Если бы ты знал язык, без всякого углубления в advanced фичи — ты бы никогда не запутался.
dot>Да знаю я язык прекрасно, опыта 5+ лет, просто уже несколько лет не использовал на работе.

Так ведь по-разному используют. Есть действительно много когда где лепят *_ptr на каждый чих. Виной тому отчасти например некоторые книги — есть авторы которые пишут сразу по трём языкам C++/C#/Java, просто копируя примеры с небольшими изменениями из книги в книгу. И отчасти те кто застрял в начале 90-х.

EP>>Это типичный миф обитающий в среде Java/C# — мол на каждый наш new, будет какой-нибудь *_ptr в C++.

dot>... либо битый указатель.

*_ptr не спасают от битых указателей, их основанная цель это выражение семантики владения в коде, отсюда и имена shared/unique/scoped.

dot>Тут ведь как:

dot>было
dot>
dot>void showDialog()
dot>{
dot>  Widget g;
dot>  ...
dot>  doer.doSomething(g);
dot>  ...
dot>}
dot>

dot>//и вдруг мы решили поменять имплементацию doSomething чтобы что-то делалось в другом треде, и мы знаем, что он завершится до закрытия диалога. А потом вдруг тред стормозил или появился другой способ закрытия диалога...

Это изменение контракта, которое прекрасно выражается в системе типов — у doSomething поменяется тип параметра и приведённый код не скомпилируется

dot>>>>>

массив не убегает за пределы, то при выходе из стека объект грохнется


EP>>>>Каким образом грохнется? Речь только про некомпактифицируемые кучи?
dot>>>Самое тривиальное — копирующим GC.
EP>>Каким образом? Положили в память эти non-escape данные, дальше вызвали какую-нибудь стороннюю функцию (не давая ей наши non-escape) — она сделала дальше какие-то аллокации, которые пошли следом за нашими non-escape данным.
EP>>Выходим из scope — дальше какие действия? Какое преимущество даст EA в этом случае?
dot>Тем что объект пойдёт на стек или в регистры. Какие аллокации?

Ещё раз. Прочитай свои слова выше (выделено), и ниже:

dot>Перенос объекта на стек это другая оптимизация. Может делаться только для маленьких оъбектов. Если у тебя выделяется 100мб массив и EA покажет, что ссылка на массив не убегает за пределы, то при выходе из стека объект грохнется. Т.е. по сути тот же unique_ptr.

Теперь скажи каким образом здесь поможет EA.

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

EP>>>>>>Smart-pointer'ы прежде всего помогают избавиться от голых владеющих указателей, а не от того что ты подумал.
dot>>>>>Бррр... Я уж надеялся, что голые указатели постепенно изничтожаются.
EP>>>>Ты что, они же есть в реальности данной нам в ощущениях железом. Это же например самый быстрый способ указать на конкретный элемент массива, или передать куда-нибудь его часть.
dot>>>Железом нам даны адреса, а не указатели.
EP>>А указатель что по-твоему хранит?
dot>Указатель ещё тип имеет. Ссылка в яве тоже адрес хранит и чё.

Конечно, и в типе разница — на C++ можно иметь указатель на элемент массива, на Java — нет.

dot>>>>>Это же сценарий high throughput, а не low latency. В такой ситуации и C++ грохнется — он будет делать ту же работу, просто в рабочих тредах, а на в отдельных gc-тредах как java.

EP>>>>Не грохнется — у него нет зависимости O(N) от количества живых объектов.
dot>>>new/malloc и delete/free работают не за O(1) внезапно.
EP>>Например для Buddy Allocation сложность логарифмическая. Есть же в том числе и O(1) алгоритмы, например TLSF.
dot>Так и разные алгоритмы GC есть. И столько всего можно крутить... И я уверен, что вариантов даже больше, ибо ссылка в jvm более абстрактна чем указатели в плюсах, а значит больше простора для оптимизаций.

Так вот покажи GC не с сублинейной сложностью, желательно ещё чтобы был более-менее популярен.

dot>>>Quick-sort имеет сложность O(N*N), как и пузырьковая... но это ещё ничего не значит.

EP>>Конечно значит, именно поэтому в реализациях std::sort используется introsort, которая хоть и основана на quicksort, но выдаёт линеаритмическую сложность
dot>Да, неудачный пример. Лучше рассмотреть hashtable. Сложность O(n). и что? Просто крутят использование до тех пор пока не станет почти O(1). Примерно так и с GC.

Штуки типа cuckoo hashing не на ровном месте появились.
Для hashtable есть альтернативы с гарантированной сублинейной сложностью, и там где гарантия нужна — их и используют. Причём можно комбинировать — снаружи hashtable, а внутри узлов при превышении лимита что-то логарифмическое — тогда будет суб-линейная гарантия.

EP>>>>Ты постоянно говоришь о каком-то одном use-case'ы.

EP>>>>Даже если и мало — всё равно придётся опускаться на очень низкий уровень, исключительно из-за самого языка.
dot>>>Я и не изобретаю общую теорию всего, а решаю практические задачи.
EP>>А кто-то изобретает? В Java нет структур — это практический недостаток и факт
dot>Зато он даёт больший простор для JVM/JIT/etc.

Какой простор? Всё равно есть те же int/double, с семантикой как у структур

dot>Ну вот есть структуры в C# — а толку? Где LL?


В C# свои проблемы. У тех же структур есть много ограничений. Но тем не менее они есть, и не нужно их эмулировать руками.

EP>>>>Это ты о чём?

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

Отдельный код для каждой комбинации. Конечно не смертельно, можно и на ASM'е писать рабочий код.

dot>>>Если ты про ссылочное дерево — то уже всё плохо, ибо оно не будет в памяти последовательно.

EP>>Деревья используются на практике. Хранение данных в самом узле позволяет избавится от лишней индерекции.
dot>Это какие-то очень экзотические условия, у меня не получается представить когда в ссылочном дереве лишняя индирекция может стать серьёзной проблемой.

А например в хэш-таблице?

dot>>>>>В C++ можно тоже кучу главных причин тормозов придумать. Скажем, передача by-value. Непонятно только к чему это.

EP>>>>Так тут есть простой выбор — by-value или by-reference. Это совершенно не тоже самое что и засучив рукава нарезать байт-буфера на структуры
dot>>>by-value — и тут ВНЕЗАПНО появляется O(N) от числа живых объектов.
EP>>Далеко не всегда. Да и почему внезапно-то?
dot>Настолько же ВНЕЗАПНО как и в случае с GC.

Ок, допустим, в случае чего by-value заменим, не проблема — пара закорючек.
В случае с GC что будешь делать?

dot>>>by-reference — и тут начинаются проблемы с временем жизни, засучив рукава начинаешь решать проблемы владения.

EP>>В 99.999% случаях ничего "засучивать" не нужно, и никакие *_ptr не нужны.
dot>Так в этих же случаях и в яве всё будет всё в YG, а значит никакого жуткого O(N).

Нет же, случаи принципиально разные. Где-то наверху callstack делаем:
{
    vector<Foo> many_values(N);
    // ...
    pass_by_reference(many_values);
}
ничего не "засучивая".
Этот массив, по терминам GC, спокойно может попасть под классификацию OG

dot>>>Зато гарантируется отсутствие битых ссыслок.

EP>>Да, это плюс — с этим никто не спорил
dot>Притом очень ценный плюс, что он перевешивает весь колбасокод с оффхипами и т.д.

Этот же плюс есть в C#, в котором "колбасокод" нужен реже, как раз за счёт структур

EP>>>>Да, на C++ нужно думать/помнить о владении (это не означает что каждый new на Java превращается в *_ptr).

EP>>>>Нет, уровни абстракции о которых я говорю решают далеко не только проблемы владения — они позволяют писать высокоуровневый И быстрый код.
dot>>>Это мы переходим в другую плоскость — выразительность языка, а не собственно JVM/GC. Для JVM есть и другие языки — Scala, Ceylon, Kotlin и прочее, которые позволяют и многие твои любимые абстракции.
EP>>А мы ВНЕЗАПНО не JVM обсуждаем, а вполне конкретную Java. Если брать JVM — то например если в неё скомпилировать C++ — то он там положит всех на лопатки
dot>Не положит, к сожалению. Иначе бы уже давно компилировали.
dot>Вся эта указательная магия и арифметика, юнионы, и прочий low level не может быть покрыт GC и JVM ссылками, поэтому при компиляции С/C++ память будет внутри byte[].

Конечно будет, и это одна из причин почему положит на лопатки.
Именно так и происходит
Автор: Evgeny.Panasyuk
Дата: 06.06.15
в Emscripten, который компилирует C++ в JS.
И JS кстати получается реально быстрый. На одном из тестов работает практически в два раза быстрее чем аналогичный код на C#. JS, в веб-браузере, Карл! И этом при том что в C# версии были структуры. Если же брать аналогичный код на Java — то всё будет ещё круче Можем кстати сравнить.

dot>>>Выразительность языка с другой стороны стреляет отстутсвием нормальной IDE.

EP>>Это тоже передёргивание.
EP>>Нормальные IDE есть. Да автоматический анализ кода сложнее, но сложнее не из-за выразительности, а из-за внутренних особенностей сложившихся исторически. Языку больше тридцати лет, а если брать с базу C (из которой многие недостатки и произрастают) — то больше сорока.
EP>>При этом аналогичную выразительность можно достичь не делая проблемы анализаторам.
dot>Может и можно... Я сходу не могу сделать такое заявление.
EP>>Те же структуры есть в C#.
dot>А толку-то от них...

Не нужно вручную нарезать массивы на структуры
Re[39]: Java vs C# vs C++
От: Evgeny.Panasyuk Россия  
Дата: 10.10.15 00:12
Оценка:
Здравствуйте, ·, Вы писали:

EP>>>>2. Теперь на этих ссылках будут висеть финализаторы, так? Для того чтобы знать когда очищать off-heap. То есть теперь ко всему прочему ещё и освобождение будет линейным.

dot>>>Можно и финализаторы, а можно и явно реализовать delete, как в плюсах. Какое освобождение сделаешь, такое и будет.
EP>>В итоге получаем и линейный обход живых, и линейных обход мёртвых, да ещё и второй аллокатор/деаллокатор (кстати какой?), и в довесок ещё расстрел памяти.
EP>>Круто — чё
dot>Если очень надо и до машкодов дойдёшь. Но это очень экзотические случаи.

Так дело даже не сложности создания, а в том что это всё может тормозить. То есть получается взяли самое плохое от обхода живых и мёртвых объектов — обходим все.

EP>>>>3. Лишние индерекции внутри List никуда не делись.

dot>>>List будет с большим числом элементов, иначе смысла извращаться нет. А на фоне этого большого числа данных один индирект не будет заметен в микроскоп.
EP>>Это один индерект на каждый элемент, а не просто один индерект. Разница может быть на порядки
dot>>>
dot>>>class BusinessData
dot>>>{
dot>>>  private Buffer buf;//замаплен например сразу на приходящий из сети блок байт или offheap хранилище или ещё чего.
dot>>>  private int pos;
dot>>>  int getA() {return buf.getInt(pos)}
dot>>>  int getB() {return buf.getInt(pos+4)}
dot>>>}
dot>>>

EP>>Так это же не спасает от тех же лишних индерекций которые есть в List<BusinessData>
dot>Двигаешь pos и получаешь элемент.

То есть предлагаешь не использовать List? Или писать свой?

dot>Притом чтобы это всё имело смысл — pos должен двигаться строго вперёд, до следующего элемента, это и будет оптимизация sequencial access, а какие всякие другие алгоритмы ты тут хочешь воротить?


Убрать лишние индерекции из random access — например элементарный бинарный поиск.
Та же сортировка или например min/max heap на основе массива, а-ля std::pop_heap.
Re[37]: Java vs C# vs C++
От: Evgeny.Panasyuk Россия  
Дата: 10.10.15 00:28
Оценка:
Здравствуйте, ·, Вы писали:

EP>>>>Об этом и речь — что по регионам, а не отдельным затронутым объектам. Поэтому я и сказал "малом количестве", а не в одном.

EP>>>>И то — это отслеживание имеет свою цену, которая размазывается по всему коду.
dot>>>Я уже упоминал, что gc плохо работает в случае большого числа короткоживущих и толпы долгоживущих. При наличии среднеживущих — производительность падает.
EP>>А как ты называешь объекты которые живут долго, но не до конца работы приложения?
dot>Old Gen. Данные этих объектов можно менять свободно, но не трогать сильно указатели.

Так они долгоживущие по твоей терминологии или нет?

dot>>>Это можно лечить настройкой GC, испоьзованием разных приёмов (flyweight или пулов например)

EP>>Причём тут flyweight? Объекты-то изменяются.
dot>Смотря как изменяются.

flyweight-ы обычно неизменяемые.

EP>>>>При логарифмической сложности между N=1000 и N=1000000 — разница примерно в два раза. А в случае же линейной сложности — примерно в тысячу раз

EP>>>>Feel the paindifference.
dot>>>Бывает. Лечится. Алгоритмы — сила.
EP>>Конечно сила, о чём я тебе и говорю.
EP>>И при логарифмической сложности, и при линейной, чем больше N тем медленнее — но разница между ними колоссальная. И в результате ситуации совершенно разные, а ты говоришь "тоже не поздоровится"
dot>Так вот строгость ссылок явы позволяет применять гораздо более хитрые алгоритмы.

Например?

EP>>>>А зачем обмениваться практически мёртвыми объектами?

dot>>>В смысле? Какие уж есть.
EP>>Контекст потерял? Ещё раз.
EP>>У нас есть объект, счётчик ссылок которого ушёл в ноль. Так? Зачем обмениваться им с другими рабочими потоками?
dot>Так ты не знаешь в каком именно потоке и когда он уйдёт в ноль и что именно произойдёт в момент ухода в ноль. В этом и суть GC. Да, узнать можно, но это очень трудоёмко. Компьютер с этим справляется в подавляющем большинстве случаев лучше и надёжнее.

Ещё раз, зачем обмениваться практически мёртвыми объектами между рабочими потоками?

EP>>>>Критический поток поставит его в очередь, а сам удалять не будет.

dot>>>И возникнет та же проблема, которой ты меня мучил — а что если он будет ставить в очередь быстрее, чем эта очередь разгребаться?
EP>>Проблема вообще-то была в другом. Если по аналогии — в том что грубо говоря pop одного элемента очереди линейно зависит от её размера. Здесь же такой зависимости нет.
dot>Не одного элемента, а всей очереди. GC за цикл собирает не один объект.

Чтобы убрать малое колличество мусорных объектов, GC приходится обходить большое количество живых. И скорость сбора мусорных объектов зависит от количества живых. В этом и аналогия.

dot>>>>>>>Хорошо, не подзадача, а средство достижения заявленных характеристик.

EP>>>>>>Короче, не нужно сами эти средства называть GC. Другой пример — копирующий аллокатор может быть без GC.
dot>>>>>Я говорю это к тому, что эти средства уже доступны при использовании GC.
EP>>>>Аналогия: "когда нарезаешь массив на структуру, переизобретаешь C++"
dot>>>Не С++. Почему именно С++, а не С, не Алгол, не Фортран, не Паскаль, не ассемблер?
EP>>Аналогично — а почему тогда GC?
dot>Потому что управление памятью — трудоёмкий процесс в прикладных приложениях. Автоматизировать его — дело святое.
EP>>Какой объем реализации? На C++ — меньше ста строк.
dot>Ну вот... сейчас ещё начнём строки считать... увольте.

Достаточно грубой прикидки. Если объём отличается на порядки — то с тем же успехом можно и компилятор модифицировать.

EP>>Да и не сравнится ведь:

EP>>
EP>>@m int meters = 5 * UnitsTools.m;
EP>>

EP>>vs
EP>>
EP>>auto length = 5m;
EP>>

EP>>Да и нет интеграции в систему типов — например перегрузка не работает
dot>Перегрузка чего? Это же примитивы.

На C++ это отдельные типы. И по разным типам можно сделать разные перегрузки.

dot>И вообще, чего опять о языке, мы же о GC вроде? Ну возьми Скалу, там есть перегрузка.


Ты же сказал что "и прочие С++ фишки можно реализовать в java" — мы в этой ветке сейчас и находимся.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.