Здравствуйте, Ночной Смотрящий, Вы писали:
I>>На мой взгляд диалог гораздо эффективнее, т.к. обе стороны предлагают варианты, задают вопросы, уточняют, поясняют и тд.
НС>Не, диалог гораздо эффективнее, когда не придумываешь себе удобного собеседника, и не выдаешь бездоказательные заявления в надежде, что собеседник кинется их опровергать.
Для начала, ты отказался пояснять свои утверждения. А я поделился своим видением. Похоже, для тебя это как тряпка на быка
I>>Как забавно — ты снова переключился на другой пример, с иммутабельностью. НС>Да пофик. Ты опять не понял что я написал.
Разумеется, мне непонятно и я прямо об этом говорю. И непонятно прежде всего потому, что ты соскочил на другой пример.
I>>Цитирую себя "пример про удаление элементов в методе add(который ты старательно "забываешь").
НС>Ты даже не дочитал сообщение до конца НС>
НС>и чего ты там еще со своимм методом add
Еще раз — пример про add никакого отношения к иммутабельности не имеет.
Выглядит так, будто пример с иммутабельностью тебе не нравится, и другой пример, с add, тебе тоже не нравится.
Свой пример ты приводить отказываешься
И каким чудом мне понять тебя?
I>>Ты бы вместо доказательства попробовал внятно изложить свои мысли, слова пояснять примерами. Глядишь, стало бы понятнее. НС>Мысль была изложена в самом начале. Не стоит пихать в структуры наследование, когда даже в классах с этим наследованием проблемы. Что тебе в этой простой мысли непонятно?
Всё непонятно — какие именно проблемы в классах. Сначала у тебя была проблемой связь is, а потом выяснилось, что не is, а эмуляция композиции. Что же ты имел ввиду — а хрен его знает.
>>Не надо сочинять — пример с add никакого отношения к иммутабельности не имеет. НС>А я где то утверждал что имеет? Ты опять споришь с воображаемым собеседником.
На мой взгляд, здесь ничего про иммутабельность нет, в явном виде речь про другой пример про очиству в методе add
Тем не менее, тебе мерещится именно иммутабельность — http://rsdn.org/forum/flame.comp/8091000.1
Здравствуйте, Ikemefula, Вы писали:
I>Еще раз — пример про add никакого отношения к иммутабельности не имеет.
Еще раз — ты с кем сейчас споришь?
I>Всё непонятно — какие именно проблемы в классах.
Я отвечал на этот вопрос в топике уже два раза. И даже ссылку потом из педивикии привел.
I>>>Снова полезла телепатия. НС>>Нет, факты. I>Покажи этот факт, где я пытаюсь чего то приписать тебе.
Да вот прям тут утверждаешь, что я, якобы, говорил что пример с add имеет отношение к иммутабельности.
... << RSDN@Home 1.3.17 alpha 5 rev. 62>>
Re[64]: MS забило на дотнет. Питону - да, сишарпу - нет?
Здравствуйте, Sinclair, Вы писали:
V>>Простого двоичного. S>Смотря как организовано это простое двоичное дерево. Если в нём известны точные типы, то да. S>А если там опять виртуальный вызов — то всё грустно.
В двоичном дереве все узлы одинаковые, т.е. виртуальность не нужна.
S>В версии с двоичным поиском мы выигрываем за счёт гарантий локальности кэша. То есть весь поиск с четырьмя ветвлениями происходит без какого-либо обмена с памятью; для случайно организованного двоичного дерева это не так.
Ну вот как раз джависты показывали, что после уплотнения GC узлы подобных объектов располагаются в памяти рядом, т.к. доступны по ссылкам только из родительских узлов, т.е. по мере естественного обхода ссылок выстроились в правильный порядок в памяти.
V>>Это еще один пункт к той моей идее, что арность узлов может расти (например, геометрически) при росте дерева вглубину, т.е. при большом кол-ве данных арность узлов-листьев будет расти. V>>Это даст что-то O(log(log(N)) S>Нет, это не даст O(log(log(N)).
Да, наврал, независимо от арности узлов-веток по ним сложность сохраняется, выигрыш только в узлах-листьях.
V>>Например, арность корня может быть небольшой в той моей идее. V>>Допустим даже 2. V>>И всегда представлять из себя узел-ветку. S>Это как раз будет убивать производительность на маленьких коллекциях.
Твои графики имеющейся дотнетной реализации показывают, что не будет.
V>>Вот тот "моноблочный" будет разный для разных глубин, если тебе удастся всё заинлайнить. S>Совершенно верно. Это именно то, чего я хочу добиться.
Попробуй ввести разные типы (одинаковые внутри) сугубо для эксперимента.
Т.е. тип Node0 порождает Node1, далее Node2 и т.д., чтобы не было псевдорекурсии.
Т.е. рост дерева будет дороже, но можно будет замерить доступ по чтению (если успешно заинлайнится), т.е. чтобы понять — стоит ли вообще копать в эту сторону.
V>>Это понятно, потому что тип известен. S>Да. И это не помогает — см. график.
Так непонятен график.
Он должен быть линейным в логарифмической шкале для имеющейся реализации.
Что такого может произойти на 256 элементах, что до него рост линейный, потом скачок, потом опять линейный рост?
Может, стоит внимательней взглянуть на происходящее в имеющемся коде?
V>>>>Хранить индекс в узле-ветке можно так, грубо: V>>>>
S>>>Вот не запуская бенчмарки вижу — не взлетит.
V>>Почему? S>Потому что не взлетает даже когда у нас "рекурсивный" вызов делается напрямую, по call CONST.
Ну ты же обогнал имеющуюся реализацию?
S>А вы предлагаете добавить косвенный вызов — который не будет предсказываться процессором.
Один косвенный вызов, в отличие от 5-ти для случая виртуального.
Косвенные вызовы тоже умеют обрабатываться предвыборкой до какой-то степени.
S>Плюс к этомк добавляем мелочи типа разрушения локальности индексов. Cell занимает 20 байт на x64, и наши index разбросаны в 320 байтах (если branchfactor == 16).
Ну, в твоей реализации индексы вынесены в отдельный bunch, что можно повторить и в этом случае.
Двоичное ветвление или линейный поиск происходит на индексах, которые в памяти рядом, а доступ к Cell (убрать оттуда поле index) происходит просто по смещению.
И там лишние 8 байт на Cell особой роли играть не будут.
V>>Красно-черный алгоритм. S>Он же только для бинарных деревьев, разве нет?
Алгоритм можно расширить на n-арное дерево.
Считай, что твой 16-арный узел — это 8 по 2, но не принципиально, пусть там было бы не 16, а 17.
Алгоритм выявляет место, где требуется произвести поворот дерева.
Здравствуйте, Serginio1, Вы писали:
S>Ага, значит TypeHandle может быть как указателем на MethodTable, так и указателем на TypeDesc, в зависимости от типа объекта. Для массивов он указывает на TypeDesc. Тип object[][] — это массив, элементами которого являются object[], для которых TypeHandle=TypeDesc. Эта информация объясняет наш пример, но всё ещё остаются некоторые вопросы. Например: а как же отличить, на что именно указывает TypeHandle? Поможет нам в этом дальнейшее изучение исходников CLI:
S>Всё зависит от второго бита в адресе: нулевое значение определяет MethodTable, а единичное — TypeDesc. Если мы работаем с шестнадцатеричными адресами, то можно легко определить вид TypeHandle по последней цифре:
Это всё тебе потребуется, если ты ручками берёшь св-во TypeHandle.
Но компилятор не берёт ничего ручками, он берёт фиксированное смещение и ничего не делает с адресом VMT, т.е. не накладывает маску в попытке обнулить младший бит.
Re[67]: MS забило на дотнет. Питону - да, сишарпу - нет?
Здравствуйте, vdimas, Вы писали:
S>>Всё зависит от второго бита в адресе: нулевое значение определяет MethodTable, а единичное — TypeDesc. Если мы работаем с шестнадцатеричными адресами, то можно легко определить вид TypeHandle по последней цифре:
V>Это всё тебе потребуется, если ты ручками берёшь св-во TypeHandle. V>Но компилятор не берёт ничего ручками, он берёт фиксированное смещение и ничего не делает с адресом VMT, т.е. не накладывает маску в попытке обнулить младший бит.
То есть для массивов это TypeDesc, а для объектов это реальный VMT
и солнце б утром не вставало, когда бы не было меня
Re[83]: MS забило на дотнет. Питону - да, сишарпу - нет?
Здравствуйте, Ночной Смотрящий, Вы писали:
I>>Еще раз — пример про add никакого отношения к иммутабельности не имеет.
НС>Еще раз — ты с кем сейчас споришь?
А я и не спорю. Раз ты продолжаешь вещать про иммутабельность, см вниз сообщения, стало быть, чтото тебя мотивирует на это. Вот мне и нужно понять, что именно вынуждает тебя перескакивать на эту иммутабельность.
Ты то свои примеры не показал, пояснять отказался, накидал каких то невнятных сообщений и хочешь, что бы я это все разгреб?
I>>Всё непонятно — какие именно проблемы в классах.
НС>Я отвечал на этот вопрос в топике уже два раза. И даже ссылку потом из педивикии привел.
Если честно, то невнятно как то: про is ты начал и бросил, про композицию начал и бросил, про полиморфизм тоже начал и бросил, сылка мягко говоря неудачная.
Что же, по твоему, гарантирует интерфейс мы так и не узнали, твоих примеров-пояснений не было
I>>Покажи этот факт, где я пытаюсь чего то приписать тебе.
НС>Да вот прям тут утверждаешь, что я, якобы, говорил что пример с add имеет отношение к иммутабельности.
Трудно понять что ты вообще говоришь. С моей точки зрения у тебя add как то связан с иммутабельностью, раз ты перескакиваешь с одного на другое. Например, в контексте про add ты притягиваешь иммутабельность. Читай сам:
Тебе показалось. То что я написал означало, что интерфейсы вполне достаточны для стандартного ОО полиморфизма. С чего ты решил что это утверждение относится и ко всяким интересным вещам типа иммутабельности — я без понятия. Поэтому мне совершенно не интересно доказывать тебе, что интерфейсов достаточно для гарантии иммутабельности и чего ты там еще со своимм методом add мне приписать пытаешься.
Более того, я тебе уже показал, почему я так думаю, цитирую себя:
На мой взгляд, здесь ничего про иммутабельность нет, в явном виде речь про другой пример про очиству в методе add
Тем не менее, тебе мерещится именно иммутабельность — http://rsdn.org/forum/flame.comp/8091000.1
Похоже, мои объяснения тебя не устраивают, примеры — не устраивают, свои предоставлять отказываешья. Чего же ты продолжаешь писать сюда? Чего тебе неймется?
У меня, наприме, ООП и её поддержка в разных ЯП обе любимые темы. Вот я и строчку. А ты то чего стараешься, если пояснять, выяснять, приводить примеры тебе впадлу?
Re[74]: MS забило на дотнет. Питону - да, сишарпу - нет?
the C# compiler changes required to support assignment of lambda expressions containing those language constructs to an Expression<TDelegate> is maintained separately in the ExpressionTrees branch of my Roslyn fork.
S>То есть сами Expression есть, а вот компилятор их порождать не умеет.
О чём и речь.
Потому что у меня изначально, еще с выходом Linq, появилась идея попробовать подставить свои Expression, типа как можно делать свой AsyncMethodBuilder, но я не нашёл как.
У меня были свои наработки по "работающему" AST, свои Add/Mul/Const и т.д.
Что-то вроде:
interface IOperation<TResult>
{
TResult Execute();
}
IBinaryOp<TLeft, TRight, TResult> : IOperation<TResult>
where TLeft : IOperation<TLeft>
where TRight: IOperation<TRight>
{
public TLeft Left {get;}
public TRight Right {get;}
}
struct Const<T> : IOperation<T>
{
public readonly T Value;
public T Execute() => Value;
}
class Variable<T> : IOperation<T>
{
public T Value;
public readonly string Name;
public T Execute() => Value;
}
struct AddIntOp<TLeft, TRight> : IBinaryOp<TLeft, TRight, int>
where TLeft : IOperation<int>
where TRight: IOperation<int>
{
public TLeft Left {get;}
public TRight Right {get;}
public int Execute() => Left.Execute() + Right.Execute();
}
Выражение с параметром x + 42
порождает тип: AddInt<Variable<int>, Const<int>>
Т.е. тоже пользовал тот факт, что джит для value-типов генерит уникальный код без боксинга.
Довольно шустро считало, кстате.
V>>Т.е. блоки для Expression нельзя. S>Да, это хорошо известный факт. Мы это обсуждали в прошлый раз в ветке про linq2d.
Блоки содержатся в объектной иерархии Expression, просто не покрыты компилятором.
И еще много чего содержится, что не покрыто.
S>С точки зрения применения Expression Trees для разнообразной работы вроде "Давайте пользователь соберёт абстрактный pipeline обработки каких-то данных, а я из него сделаю монолитный эффективный метод без лишних аллокаций" это плохо.
Именно.
S>С точки зрения "я хочу писать Queryable Provider" это хорошо. Потому, что мне не нужно писать код для обработки случаев вроде S>
S>from p in Person where {var s = new StringBuilder(); foreach(var ch in p.Name} if (p.IsLetterOrDigit) s.Append(ch); return s.ToString()=="John";} select p
S>
Но можно сделать так:
internal record Person(string Name);
private static bool MyPredicate(string name) {
var s = new StringBuilder();
foreach(var ch in name) {
if(char.IsLetterOrDigit(ch))
s.Append(ch);
}
return s.ToString() == "John";
}
private static void Main() {
Person[] persons = {
new("++John++"),
new("Jo--hn"),
new("Andy")
};
var collection = from p in persons.AsQueryable() where MyPredicate(p.Name) select p;
foreach(var p in collection)
Console.WriteLine(p);
}
Т.е., я не вижу смысла в таких ограничениях, которые обходится простым оформлением лямбды в виде внешней ф-ии.
S>Коротко, там есть два основных класса проблем: S>1. Не все языковые конструкции имеют аналог в виде Expression.
Ну, это понятно, особенно в деле unsafe.
Непонятно, почему поддержаны не все уже имеющиеся виды Expression.
S>2. Не все типы Expression (даже из стандартной библиотеки) можно породить компилятором из лямбда-синтаксиса.
Ага, в моём примере MyPredicate нельзя было объявить локальной статической ф-ией.
S>Вот это решается только коммитом в компилятор шарпа.
О чём и речь — еще пилить и пилить.
S>Актуальность каждой из проблем зависит от решаемой задачи.
А какая вообще у багов "актуальность"? ))
То, что MyPredicate не может быть статической локальной ф-ией — это просто баг, неконсистентность.
Здравствуйте, Sinclair, Вы писали:
V>>Наличие многопоточной очереди лишь одной дисциплины. V>>И применение очереди этой дисциплины не по месту. S>То есть к самой ConcurrentQueue вопросов нету. Ну, ок.
Претензии были озвучены:
Например, имеющаяся сейчас в дотнете ConcurrentQueue — тоже только поржать.
В момент роста очереди остальные потоки выполняют строго-блокированное ожидание на SpinWait.
Эта очередь не отвечает гарантиям lock-free, т.к. один поток может заморозить другие.
Re[68]: MS забило на дотнет. Питону - да, сишарпу - нет?
Здравствуйте, Serginio1, Вы писали:
V>>Но компилятор не берёт ничего ручками, он берёт фиксированное смещение и ничего не делает с адресом VMT, т.е. не накладывает маску в попытке обнулить младший бит. S>То есть для массивов это TypeDesc, а для объектов это реальный VMT
Ну, массивы — это не совсем обычные объекты.
Компилятору не требуется вызывать виртуальные методы для массивов.
А если те приведены к интерфейсу, то в любом случае идёт обращение уже к таблице интерфейсов.
Re[65]: MS забило на дотнет. Питону - да, сишарпу - нет?
Здравствуйте, vdimas, Вы писали:
V>В двоичном дереве все узлы одинаковые, т.е. виртуальность не нужна.
Да. И, похоже, даже вызовы не нужны.
V>Ну вот как раз джависты показывали, что после уплотнения GC узлы подобных объектов располагаются в памяти рядом, т.к. доступны по ссылкам только из родительских узлов, т.е. по мере естественного обхода ссылок выстроились в правильный порядок в памяти.
Это всё ещё значительно менее плотно, чем int[].
S>>Это как раз будет убивать производительность на маленьких коллекциях. V>Твои графики имеющейся дотнетной реализации показывают, что не будет.
Там если присмотреться, то для некоторых размеров мы объезжаем дотнетную реализацию. А если избавиться от гомогенности и лишних ветвлений вида IsLeaf, то будем объезжать для всех.
V>Попробуй ввести разные типы (одинаковые внутри) сугубо для эксперимента.
Это и была идея номер 2 в моём ответе.
V>Т.е. рост дерева будет дороже, но можно будет замерить доступ по чтению (если успешно заинлайнится), т.е. чтобы понять — стоит ли вообще копать в эту сторону.
Рост будет стоить ровно столько же.
V>Так непонятен график. V>Он должен быть линейным в логарифмической шкале для имеющейся реализации. V>Что такого может произойти на 256 элементах, что до него рост линейный, потом скачок, потом опять линейный рост?
Я полагаю — пересечение границы какого-то из кэшей.
S>>Потому что не взлетает даже когда у нас "рекурсивный" вызов делается напрямую, по call CONST.
V>Ну ты же обогнал имеющуюся реализацию?
Я обогнал на коде без вызовов.
V>Косвенные вызовы тоже умеют обрабатываться предвыборкой до какой-то степени.
Вряд ли.
V>И там лишние 8 байт на Cell особой роли играть не будут.
Да там не нужен этот Cell вообще. Это же B+ дерево — тип у всех детей любой ноды одинаков. Поэтому достаточно хранить ровно одну ссылку на getItem.
Но это всё ещё не поможет — даже когда вместо косвенного вызова внутри getItem стоит прямой вызов на getItem вложенного класса, производительность падает на дно.
V>Алгоритм можно расширить на n-арное дерево. V>Считай, что твой 16-арный узел — это 8 по 2, но не принципиально, пусть там было бы не 16, а 17. V>Алгоритм выявляет место, где требуется произвести поворот дерева.
Хм. Сходу не очень понимаю, как будет работать поворот небинарного дерева.
V>Речь про арность.
Речь про лишние вызовы. Они доминируют над арностью.
V>Запутал. V>Тут показывает, что у тебя доступ по this[index] хуже: V>https://github.com/evilguest/atropos/blob/main/Atropos.Benchmarks/Atropos.Benchmarks.List.IndexInt.png V>И в других сценариях тоже. V>Ранее ты показывал график, где твой код эффективней.
Я же говорю — был прошлогодний код, который работал на гомогенном дереве. Но в нём были проблемы с выделением лишней памяти в листьях. График, который я показал — оттуда.
Сейчас я пытаюсь реализовать код, в котором нет лишних данных. Технически, это получилось, но вот лишние вызовы портят всю малину.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[66]: MS забило на дотнет. Питону - да, сишарпу - нет?
Здравствуйте, vdimas, Вы писали:
V>Претензии были озвучены: V>
V>Например, имеющаяся сейчас в дотнете ConcurrentQueue — тоже только поржать.
V>В момент роста очереди остальные потоки выполняют строго-блокированное ожидание на SpinWait.
V>Эта очередь не отвечает гарантиям lock-free, т.к. один поток может заморозить другие.
Ну, в таком случае можно предьявить свою реализацию очереди, не ссылаясь на необходимость переписать полдотнета
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[75]: MS забило на дотнет. Питону - да, сишарпу - нет?
V>the C# compiler changes required to support assignment of lambda expressions containing those language constructs to an Expression<TDelegate> is maintained separately in the ExpressionTrees branch of my Roslyn fork.
S>>То есть сами Expression есть, а вот компилятор их порождать не умеет.
V>О чём и речь. V>Потому что у меня изначально, еще с выходом Linq, появилась идея попробовать подставить свои Expression, типа как можно делать свой AsyncMethodBuilder, но я не нашёл как.
V>У меня были свои наработки по "работающему" AST, свои Add/Mul/Const и т.д. V>Что-то вроде: V>
V>interface IOperation<TResult>
V>{
V> TResult Execute();
V>}
V>IBinaryOp<TLeft, TRight, TResult> : IOperation<TResult>
V> where TLeft : IOperation<TLeft>
V> where TRight: IOperation<TRight>
V>{
V> public TLeft Left {get;}
V> public TRight Right {get;}
V>}
V>struct Const<T> : IOperation<T>
V>{
V> public readonly T Value;
V> public T Execute() => Value;
V>}
V>class Variable<T> : IOperation<T>
V>{
V> public T Value;
V> public readonly string Name;
V> public T Execute() => Value;
V>}
V>struct AddIntOp<TLeft, TRight> : IBinaryOp<TLeft, TRight, int>
V> where TLeft : IOperation<int>
V> where TRight: IOperation<int>
V>{
V> public TLeft Left {get;}
V> public TRight Right {get;}
V> public int Execute() => Left.Execute() + Right.Execute();
V>}
V>
V>Выражение с параметром V>x + 42 V>порождает тип: V>AddInt<Variable<int>, Const<int>> V>Т.е. тоже пользовал тот факт, что джит для value-типов генерит уникальный код без боксинга. V>Довольно шустро считало, кстате.
А зачем это всё, после C# 3.0? Уж с add int у них нету проблем.
V>Т.е., я не вижу смысла в таких ограничениях, которые обходится простым оформлением лямбды в виде внешней ф-ии.
По большому счёту, его и нет.
V>Ну, это понятно, особенно в деле unsafe. V>Непонятно, почему поддержаны не все уже имеющиеся виды Expression.
Есть подозрение, что тупо не выделили ресурсов. Типа "EF работает? Работает. Ну и всё, оставьте лямбды в покое".
V>А какая вообще у багов "актуальность"? ))
Очень простая. V>То, что MyPredicate не может быть статической локальной ф-ией — это просто баг, неконсистентность.
Если в моём проекте нет нужды использовать в предикате локальную статик функцию, то мне на эту неконсистентность наплевать.
Вот с вашей точки зрения, експрешшны ещё "пилить и пилить", а с моей точки зрения linq2d уже работает прямо сейчас. На позапрошлой версии компилятора.
А с точки зрения производителя, ц каждой неконсистентности есть две оценки: стоимости починки и выигрыша от починки.
Второе напрямую зависит от тяжести последствий, частоты встречаемости, и наличия воркэраундов. К сожалению, на их весах конкретно поддержка локал статик функций приносит примерно 0 пользы при ненулевой себестоимости.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[76]: MS забило на дотнет. Питону - да, сишарпу - нет?
Здравствуйте, Sinclair, Вы писали:
S>А зачем это всё, после C# 3.0?
Пи чём тут C# 3.0?
Экспериментировал я с выходом linq.
S>Уж с add int у них нету проблем.
Специально не делал то замечание, что сейчас арифметические операторы можно делать в генериках.
С тобой же не раз обсуждали способы решения этой задчи.
V>>Т.е., я не вижу смысла в таких ограничениях, которые обходится простым оформлением лямбды в виде внешней ф-ии. S>По большому счёту, его и нет.
Не выспался? ))
V>>То, что MyPredicate не может быть статической локальной ф-ией — это просто баг, неконсистентность. S>Если в моём проекте нет нужды использовать в предикате локальную статик функцию, то мне на эту неконсистентность наплевать.
Такое ощущение, что ты не понимаешь, что пишешь.
На пальцах: статические локальные ф-ии ввели относительно недавно.
Походу, под эту новую фичу не успели доработать некий внутренний ExpressionBuilder.
S>Вот с вашей точки зрения, експрешшны ещё "пилить и пилить", а с моей точки зрения linq2d уже работает прямо сейчас.
Как ты ставил эксперименты, никто так с Linq не работает.
S>А с точки зрения производителя, ц каждой неконсистентности есть две оценки: стоимости починки и выигрыша от починки.
Рассуждая так, дешевле совсем ничего не делать.
Основная странность тут в том, что похвастаться новой фичей не забыли.
S>Второе напрямую зависит от тяжести последствий, частоты встречаемости, и наличия воркэраундов.
К сожалению, на их весах конкретно поддержка локал статик функций приносит примерно 0 пользы при ненулевой себестоимости.
Re[77]: MS забило на дотнет. Питону - да, сишарпу - нет?
Здравствуйте, vdimas, Вы писали:
V>Пи чём тут C# 3.0? V>Экспериментировал я с выходом linq.
Ну вот он и вышел в C# 3.0. Зачем иметь свои IOperation<Result>, когда есть Expression<Func<Result>>?
Зачем AddIntOp<TLeft, TRight>, когда можно просто сделать Expression.Add(Expression.Variable(typeof(int), "x"), Expression.Constant(42))?
Вызываем на нём Compile(), и получаем полноценный бинарный код, ничуть не хуже, чем у AddIntOp.Execute().
V>Специально не делал то замечание, что сейчас арифметические операторы можно делать в генериках. V>С тобой же не раз обсуждали способы решения этой задчи.
Это вообще ортогональная задача. Арифметические операторы в интерфейсах позволяют нам делать арифметические функции типа T Sum(IEnumerable<T> operands).
Деревья выражений и без этого позволяли нам строить код динамически.
V>Такое ощущение, что ты не понимаешь, что пишешь.
V>На пальцах: статические локальные ф-ии ввели относительно недавно. V>Походу, под эту новую фичу не успели доработать некий внутренний ExpressionBuilder.
Эмм, по-моему, кто-то отстаёт от дискуссии. Некий внутренний ExpressionBuilder "не успели" доработать до примерно всего, что появилось после C# 3.0.
Это выглядит не как "неуспевание", а как намеренное решение не копать в эту сторону.
При этом важно понимать, что "внутренняя целостность" сама по себе имеет исключительно академическую ценность.
В реальных проектах решения принимаются исходя из практической, а не академической ценности. Вот, скажем, неумение использовать в деревьях выражений статик локалы аффектит примерно 0 человек в мире.
И для тех, кто на это напоролся, есть простой рецепт: перенесите статик локал в простой приватный статик. Всё, вопрос закрыт.
Альтернатива — давайте расширим библиотеку, расширим компилятор, допишем тесты. А, да, самое главное — ресурсы ограничены, поэтому чтобы сделать это, придётся не сделать что-то другое.
Ну вот и не нашлось никакой фичи в бэклоге, которая была бы нужна меньше, чем эта. Увы.
V>Как ты ставил эксперименты, никто так с Linq не работает.
Ну, "если вы хотите добиться успеха, вы должны быть готовы делать то, чего не хотят делать другие". Мне важно то, что "торчит наружу". Поэтому какие-то внутренние проблемы linq2d имеют низкую важность.
Вот отсутствие в ExpressionTrees тупл-инициализаторов торчит прямо наружу, и это мешает потенциальным клиентам linq2d.
V>Рассуждая так, дешевле совсем ничего не делать.
Нет. Отсутствие некоторых фич приносит прямой или косвенный убыток. Или, наоборот, допиливание каких-то фич может принести пользу большому количеству людей.
Так и принимаются продуктовые решения — постоянно приходится чем-то жертвовать.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[78]: MS забило на дотнет. Питону - да, сишарпу - нет?
Здравствуйте, Sinclair, Вы писали:
V>>Экспериментировал я с выходом linq. S>Ну вот он и вышел в C# 3.0. Зачем иметь свои IOperation<Result>, когда есть Expression<Func<Result>>?
Потому что мои Op выполняются, считай, сразу, без стадии компиляции в CIL на моей стороне.
S>Вызываем на нём Compile(), и получаем полноценный бинарный код, ничуть не хуже, чем у AddIntOp.Execute().
Берём серверную сторону, сервак работает 24x7.
Серверная сторона не для красного словца — та задача изначально под серверную сторону потребовалась.
Compile каждый раз порождает новый код, который остаётся в памяти процесса и нет способа этот мусор собрать.
Перезагрузки доменов теперь тоже нет.
Сравни с моим подходом, где семантически одинаковые выражения представлены одинаковым типом, т.е. кол-во бинарного кода растёт лишь по мере роста разнообразия выражений.
Это примерно как в случае роста твоего B+ дерева.
Рост сложности выражений я ограничил на уровне 5 через боксирование, т.е. использование периодически чистых интерфейсов во время построения типа.
Хотя, и глубины 5 на практике достигалось редко.
V>>Специально не делал то замечание, что сейчас арифметические операторы можно делать в генериках. V>>С тобой же не раз обсуждали способы решения этой задчи. S>Это вообще ортогональная задача. Арифметические операторы в интерфейсах позволяют нам делать арифметические функции типа T Sum(IEnumerable<T> operands).
Через тип-словарик это можно было делать и раньше, но конкретно в этой задаче генерик-реализация экономила мало, бо в том "калькуляторе" использовалось два числовых типа всего — целочисленный long и double. Int — это я просто суть происходящего показывал на пальцах. И обслуживать те типы "раздельно" тоже было удобно, бо напрямую long и double не взаимодействуют в арифметических операциях, а только через предварительную промежуточную операцию приведения long к double, т.е. простой if в коде парсера-билдера оперирует не-генерик типами, а обычными, что тоже где-то удобно, в отсутствии протягиваемого для type-билдера лишней пары генерик-параметров (T и TOpProvider where TOpProvider : IOpProvider<T>).
V>>На пальцах: статические локальные ф-ии ввели относительно недавно. V>>Походу, под эту новую фичу не успели доработать некий внутренний ExpressionBuilder. S>Эмм, по-моему, кто-то отстаёт от дискуссии.
Да нет, это ты ответвился от сути моих замечаний.
Замечаний два, они взаимосвязаны:
— Expression вшит в C# и нет возможности подставить некий свой expression builder для ламбд;
— сам ExpressionBuilder обслуживает не все виды лямбд, хотя именно для их обслуживания создавался.
S>Некий внутренний ExpressionBuilder "не успели" доработать до примерно всего, что появилось после C# 3.0.
S>Это выглядит не как "неуспевание", а как намеренное решение не копать в эту сторону.
А что там надо копать для использования объявленного в методе вложенного статического метода?
Чем этот статический метод отличается от обычного?
Насколько я знаю — только именем со специальными префиксами, что-то типа "SomeClass::SomeMethod<>InternalMethod".
Т.е., переименуй SomeClass::SomeMethod<>InternalMethod в SomeClass::SomeMethod_InternalMethod и всё работает.
S>При этом важно понимать, что "внутренняя целостность" сама по себе имеет исключительно академическую ценность.
Не, важно понимать, что вопросы планирования, раздачи приоритетов, оценки трудоёмкости тех или иных вещей — это одна из важнйших стадий в любой инженерной разработке.
Этот факап не фатален, конечно, просто показывает, что у дотнета, оказывается, нет няньки.
Т.е., опен-сорсная реализация не означала отказ от няньчанья, но, похоже, с дотнетом происходит именно это.
Например, гугл строго няньчится со своим Хромом, хотя проект и в опен-сорсе.
S>В реальных проектах решения принимаются исходя из практической, а не академической ценности.
В реальных коммерческих проектах всегда весы — трудоёмкость vs получаемые плюшки.
Т.е. задачи сортируются не только по степени их важности, но и по соотношению цена:качество.
Чем лучше это соотношение, тем больший балл прибавляется к приоритету задачи.
А здесь ситуация вдвойне забавной получилась, бо поддержка статических локальных методов в expression builder не стоит дороже написания нового кода, который сгенерирует и выдаст новую ошибку компиляции с новым номером при попытке использовать статические локальные методы в expressions.
S>Вот, скажем, неумение использовать в деревьях выражений статик локалы аффектит примерно 0 человек в мире.
Опять эта ущербность вопреки здравому смыслу...
Как-то странно тебя колбасит от полёта фантазии в далекий коммунизм, где всё по-уму и давно хорошо работает, до полной деградации, до отказа даже от малого.
Рассуждения в таком духе заведомо ущербны, почему ты сам этого не видишь?
Рассуждая похожим образом:
— отсутствие linq в дотнете аффектило примерно 0 человек в мире
— отсутствие дотнета аффектило примерно 0 человек в мире
— и т.д.
Посмотри в зеркало, плиз, на каждый именно твой пост запросто можно отвечать "это никому не нужно" и "ты всё-равно до этого не доживёшь", бо ты пишешь сюда именно такой материал, заведомо допускающий именно таких оценок.
S>И для тех, кто на это напоролся, есть простой рецепт: перенесите статик локал в простой приватный статик. Всё, вопрос закрыт.
А зачем это делать ручками, если комплятор и так переносит статик локал в простой приватный статик? (в отличие от нестатик локал)
Т.е. суть именно в этом — фича уже готова и работает, ничего даже делать не надо.
Дописать тесты им пришлось в любом случае.
Тесты на правильное генерирование ошибок, хотя бы.
S>А, да, самое главное — ресурсы ограничены, поэтому чтобы сделать это, придётся не сделать что-то другое.
Я думаю, что там всё малость проще.
Вряд ли дотнетные разработчики действительно сошли с ума, скорее, они рассматривают дотнетное сообщество как сборище инфантильных детей.
Им заранее облом отвечать на вопросы из разряда "а почему статические локальные ф-ии в linq использовать можно, а нестатические нет?".
Вот и весь секрет.
S>Ну вот и не нашлось никакой фичи в бэклоге, которая была бы нужна меньше, чем эта. Увы.
Что лишний раз напоминает о том, что ты плохо разбираешься в мотивации других людей.
Отчасти это объясняет странные пробуксовки в обсуждении с тобой на ровном месте.
Среди активных участников наших баталий я выделяю двух коллег, у которых необъяснимый провал в деле формулирования задач.
Как вообще можно работать инженером с низким таким навыком?
(при том, что многие жестко оппонирующие мне умеют это великолепно, тот же НС, т.е. дело тут не в совпадении или нет взглядов).
V>>Как ты ставил эксперименты, никто так с Linq не работает. S>Ну, "если вы хотите добиться успеха, вы должны быть готовы делать то, чего не хотят делать другие".
Это формула мотивации при полученной высокой оценки трудоёмкости/наукоёмкости некоей задачи.
К делу формулирования задач это перпендикулярно.
"Угадать" тут можно разве что случайно, когда собственный интерес совпадёт с фактическими потребностями.
Ведь именно тут инженерия отличается от исскуства, хотя обе работы творческие, созидательные.
S>Вот отсутствие в ExpressionTrees тупл-инициализаторов торчит прямо наружу, и это мешает потенциальным клиентам linq2d.
Разве?
Тебе можно вернуть твои же возражения — решается так-то и так-то.
Func<(int, int)> f = ()=>(42, 42);
Expression<Func<(int, int)>> f1 = ()=> ValueTuple.Create(42, 42);
Причём, сравнение ValueTuple появилось только в C# 7.3, т.е., проблема в том, что уже имеющийся Tuple — это класс, поэтому, сделали новый тип ValueTuple<> и сущность tuple literal.
Т.е. этой функциональности в Expression банально нет, её надо пилить.
Я же рассуждал о том, что уже есть, но не доступно.
V>>Рассуждая так, дешевле совсем ничего не делать. S>Нет. Отсутствие некоторых фич приносит прямой или косвенный убыток. Или, наоборот, допиливание каких-то фич может принести пользу большому количеству людей. S>Так и принимаются продуктовые решения — постоянно приходится чем-то жертвовать.
Как принимаются решения я уже показывал выше.
Решения принимаются в несколько этапов, происходящих итеративно: из формулирования целей и приоритетов, затем из анализа потенциальной трудоёмкости задач, соотнесения с располагаемыми ресурсами, goto на начало.
Т.е., процесс принятия решений итеративный и непрерывный, обновляемый в т.ч. по мере фактического достижения тех или иных целей, изменений в ресурсах, изменений в стоимости решения тех или иных задач и т.д.
Поэтому, твои рассуждения "вот это надо, а это не надо" я воспринимаю как отрыв от объективной реальности, сорри (впрочем, как и всегда с тобой).
У каждого "надо" есть цена, где в отсутствии рассмотрения цены рассуждения о надобности профанируются.
Здравствуйте, Sinclair, Вы писали:
V>>Эта очередь не отвечает гарантиям lock-free, т.к. один поток может заморозить другие. S>Ну, в таком случае можно предьявить свою реализацию очереди, не ссылаясь на необходимость переписать полдотнета
Это называется заблудиться в трёх соснах. ))
Я уже подсказал, где можно найти аналогичную реализацию очереди, свой исходник вряд ли имею право дать.
(да и смысла нет, если аналог доступен в открытом доступе)
И что было непонятного в том замечении, что очередь с той дисциплиной потребует переписать механизм тасков?
Это попытка замылить суть вопроса или что?
Альтернативные lock-free очереди с дисциплиной многие-ко-многим на этом сайте тоже публиковались неоднократно, только при чём тут они, если эта дисциплина банально не нужна в деле огранизаций очередей к конкретным потокам?
Re[66]: MS забило на дотнет. Питону - да, сишарпу - нет?
Здравствуйте, Sinclair, Вы писали:
V>>Ну вот как раз джависты показывали, что после уплотнения GC узлы подобных объектов располагаются в памяти рядом, т.к. доступны по ссылкам только из родительских узлов, т.е. по мере естественного обхода ссылок выстроились в правильный порядок в памяти. S>Это всё ещё значительно менее плотно, чем int[].
На быстродействие влияет не только кеш нулевого уровня, который у каждого ядра личный.
Кеш нулевого уровня влияет на быстродействие я уже напоминал где — это когда иммутабельные типы заползают на ту линейку кеша, в которых расположены активно изменяемые данные. В этом случае иммутабельность профанируется с т.ч. железа. И эта задача всё-равно еще не решена у тебя.
Т.е., тебе пока требуется "просто локальность", а в ней разница в 64 байта или 1кб практически отсутствует в разогретом кеше.
S>>>Это как раз будет убивать производительность на маленьких коллекциях. V>>Твои графики имеющейся дотнетной реализации показывают, что не будет. S>Там если присмотреться, то для некоторых размеров мы объезжаем дотнетную реализацию.
Я не вижу на графиках объезжания на малых объемах данных, но ты утверждаешь обратное.
V>>Т.е. рост дерева будет дороже, но можно будет замерить доступ по чтению (если успешно заинлайнится), т.е. чтобы понять — стоит ли вообще копать в эту сторону. S>Рост будет стоить ровно столько же.
Это с большой копипастой.
Я бы для простоты сделал на виртуальных методах или if-ах с последующим разбоксированием.
Это же все-равно лишь эксперимент для замера эффективности другой функциональности.
V>>Так непонятен график. V>>Он должен быть линейным в логарифмической шкале для имеющейся реализации. V>>Что такого может произойти на 256 элементах, что до него рост линейный, потом скачок, потом опять линейный рост? S>Я полагаю — пересечение границы какого-то из кэшей.
Когда просто по чтению?
Та граница должна будет пересечься и у тебя в каком-то месте.
Можно было бы повторить замеры с предварительным full GC после наполнения дерева.
S>>>Потому что не взлетает даже когда у нас "рекурсивный" вызов делается напрямую, по call CONST. V>>Ну ты же обогнал имеющуюся реализацию? S>Я обогнал на коде без вызовов.
Код без вызовов не объясняет отклонение от log(N).
V>>Косвенные вызовы тоже умеют обрабатываться предвыборкой до какой-то степени. S>Вряд ли.
Обрабатываются по-факту на один уровень косвенности, если содержимое целевого слота памяти независима от текущих вычислений.
V>>И там лишние 8 байт на Cell особой роли играть не будут. S>Да там не нужен этот Cell вообще. Это же B+ дерево — тип у всех детей любой ноды одинаков. Поэтому достаточно хранить ровно одну ссылку на getItem.
А да, в твоей релизации одинаковы.
Тем более.
S>Но это всё ещё не поможет — даже когда вместо косвенного вызова внутри getItem стоит прямой вызов на getItem вложенного класса, производительность падает на дно.
Но в дотнетной реализации именно это?
V>>Алгоритм можно расширить на n-арное дерево. V>>Считай, что твой 16-арный узел — это 8 по 2, но не принципиально, пусть там было бы не 16, а 17. V>>Алгоритм выявляет место, где требуется произвести поворот дерева. S>Хм. Сходу не очень понимаю, как будет работать поворот небинарного дерева.
При повороте дочерний узел заменяет собой родительский узел.
В иммутабельном виде как таковой "замены" нет, есть перестроение подиерархии.
Красно-черные позволяют при перестроении перестраивать ограниченное кол-во узлов, т.к. допускается разница в уровнях в 1 по разным веткам.
А у тебя при росте вложенности потребуется перестроить всё дерево, насколько я сейчас понял.
V>>Речь про арность. S>Речь про лишние вызовы. Они доминируют над арностью.
Не только...
В мутабельном B+ дереве легко последовательно обойти хранящиеся значения (один из основных кейзов для списка), т.к. все листья соеденены в связанный список.
В иммутабельном виде этой функциональности нет, насколько я понимаю, поэтому обход достаточно дорогой.
S>Я же говорю — был прошлогодний код, который работал на гомогенном дереве. Но в нём были проблемы с выделением лишней памяти в листьях. График, который я показал — оттуда. S>Сейчас я пытаюсь реализовать код, в котором нет лишних данных. Технически, это получилось, но вот лишние вызовы портят всю малину.
Попробуй опять с гомогенными узлами.
Там никакая рекурсия не нужна, вирутальность на верхнем уровне тоже, просто сдвигаешься в цикле до листового узла.
Причём, твой узел заведомо "знает", ссылается ли он на листья или ветки, это один флаг.
Затем можно приводить ссылку на дочерний узел через Unsafe.As<T>(Object).
Смотри какие фокусы выдаёт:
class Box<T>
where T : struct
{
public readonly T Value;
public Box(T value) => Value = value;
}
class Box {
public static Box<T> From<T>(T value) where T : struct => new(value);
}
private static void Main() {
object boxedDouble = Box.From(1.0);
var boxedLong = Unsafe.As<Box<long>>(boxedDouble);
var doubleBits = boxedLong.Value;
var isPositive = (doubleBits & 1L << 63) == 0;
}
Re[79]: MS забило на дотнет. Питону - да, сишарпу - нет?
Здравствуйте, vdimas, Вы писали:
V>Потому что мои Op выполняются, считай, сразу, без стадии компиляции в CIL на моей стороне.
Ну, ок. Статика. Если удастся сконструировать их статически.
S>>Вызываем на нём Compile(), и получаем полноценный бинарный код, ничуть не хуже, чем у AddIntOp.Execute().
V>Берём серверную сторону, сервак работает 24x7. V>Серверная сторона не для красного словца — та задача изначально под серверную сторону потребовалась. V>Compile каждый раз порождает новый код, который остаётся в памяти процесса и нет способа этот мусор собрать.
А зачем делать это каждый раз, когда можно один раз проинициализировать статическое поле результатом Compile, а потом обращаться к нему за стоимость вызова IOperation<int>.Execute или даже быстрее? V>Перезагрузки доменов теперь тоже нет.
Почему не скомпилировать это в DynamicMethod, который прекрасно соберётся безо всякой выгрузки доменов?
V>Через тип-словарик это можно было делать и раньше, но конкретно в этой задаче генерик-реализация экономила мало, бо в том "калькуляторе" использовалось два числовых типа всего — целочисленный long и double. Int — это я просто суть происходящего показывал на пальцах. И обслуживать те типы "раздельно" тоже было удобно, бо напрямую long и double не взаимодействуют в арифметических операциях, а только через предварительную промежуточную операцию приведения long к double, т.е. простой if в коде парсера-билдера оперирует не-генерик типами, а обычными, что тоже где-то удобно, в отсутствии протягиваемого для type-билдера лишней пары генерик-параметров (T и TOpProvider where TOpProvider : IOpProvider<T>).
Эмм, если где-то есть парсер-билдер, то никакой статики уже не будет.
V>Замечаний два, они взаимосвязаны: V>- Expression вшит в C# и нет возможности подставить некий свой expression builder для ламбд;
Кстати, где-то пробегал FR по внедрению расширяемого expression builder. V>- сам ExpressionBuilder обслуживает не все виды лямбд, хотя именно для их обслуживания создавался.
V>https://docs.microsoft.com/ru-ru/dotnet/csharp/whats-new/csharp-8
Нет, "списочек" — вот: https://github.com/bartdesmet/ExpressionFutures/blob/master/CSharpExpressions/README.md
V>Не, важно понимать, что вопросы планирования, раздачи приоритетов, оценки трудоёмкости тех или иных вещей — это одна из важнйших стадий в любой инженерной разработке.
А то.
V>Например, гугл строго няньчится со своим Хромом, хотя проект и в опен-сорсе.
Да, есть ещё несколько признаков того, что "няньки нет". Но это будет работать до тех пор, пока это отсутствие няньки не будет приводить к реальному геморрою реальных пользователей языка.
V>В реальных коммерческих проектах всегда весы — трудоёмкость vs получаемые плюшки.
Точно. Именно это я и написал.
V>А здесь ситуация вдвойне забавной получилась, бо поддержка статических локальных методов в expression builder не стоит дороже написания нового кода, который сгенерирует и выдаст новую ошибку компиляции с новым номером при попытке использовать статические локальные методы в expressions.
Возможно. Я в код компилятора не смотрел, не могу сказать, что было дороже.
V>Рассуждая похожим образом: V>- отсутствие linq в дотнете аффектило примерно 0 человек в мире V>- отсутствие дотнета аффектило примерно 0 человек в мире
Вот эти натянутые аналогии показывают, что вам пока рано в продакт менеджмент
Отсутствие linq в дотнете аффектило миллионы человек в мире. Хейльсберг в своё время очень убедительно обосновывал, почему был разработан Linq — а ведь это потребовало огромных инвестиций. Уж очень дофига принципиально нового было добавлено в язык.
Отсутствие дотнета аффектило, в первую очередь, позиции Microsoft, которому хотелось делать свою JVM, но Sun не давала им пилить JVM в нужную микрософту сторону. V>Посмотри в зеркало, плиз, на каждый именно твой пост запросто можно отвечать "это никому не нужно" и "ты всё-равно до этого не доживёшь", бо ты пишешь сюда именно такой материал, заведомо допускающий именно таких оценок.
Ну естественно. По умолчанию, linq2d нафиг никому не упал. Если бы я пробовал продать его идею потенциальному инвестору, то всё закончилось бы ещё до начала. V>А зачем это делать ручками, если комплятор и так переносит статик локал в простой приватный статик? (в отличие от нестатик локал) V>Т.е. суть именно в этом — фича уже готова и работает, ничего даже делать не надо.
Так это же везде так — ну возьми, замени (4, 5) на ValueTuple.Create(4, 5) — всё ж готово. Но нет, не делают.
V>Вряд ли дотнетные разработчики действительно сошли с ума, скорее, они рассматривают дотнетное сообщество как сборище инфантильных детей. V>Им заранее облом отвечать на вопросы из разряда "а почему статические локальные ф-ии в linq использовать можно, а нестатические нет?". V>Вот и весь секрет.
Вот если честно, меня вопросы внутренних процессов принятия решений не очень интересуют. Мне и так приходится ежедневно принимать рещения, которые снаружи могут выглядеть совершенно нелогичными.
V>Что лишний раз напоминает о том, что ты плохо разбираешься в мотивации других людей.
Почему вы решили, что вы разбираетесь лучше? Мы гадаем на кофейной гуще. У меня версия — feature didn't jump over the bar. Ваша идея — "лень было объяснять разницу между статик локалами и нестатик локалами".
Хотя технически я не вижу разницы между статик и нестатик локалами — всё равно строится замыкание. Если уж делать — то можно поддерживать обоих. V>Отчасти это объясняет странные пробуксовки в обсуждении с тобой на ровном месте.
V>Разве? V>Тебе можно вернуть твои же возражения — решается так-то и так-то. V>
V>Func<(int, int)> f = ()=>(42, 42);
V>Expression<Func<(int, int)>> f1 = ()=> ValueTuple.Create(42, 42);
V>
V>Решения принимаются в несколько этапов, происходящих итеративно: из формулирования целей и приоритетов, затем из анализа потенциальной трудоёмкости задач, соотнесения с располагаемыми ресурсами, goto на начало.
Именно. И вот этот процесс привёл к тем результатам, которые мы и наблюдаем.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[68]: MS забило на дотнет. Питону - да, сишарпу - нет?
Здравствуйте, vdimas, Вы писали:
V>Это называется заблудиться в трёх соснах. )) V>Я уже подсказал, где можно найти аналогичную реализацию очереди, свой исходник вряд ли имею право дать.
Смешно. Сделайте другой исходник. ГК РФ запрещает относить к служебным произведениям что-то, сделанное вне рамок должностных обязанностей или распоряжений руководства.
V>(да и смысла нет, если аналог доступен в открытом доступе)
Обожаю смотреть, как вы начинаете вертеться, как только речь заходит о реальном коде.
V>И что было непонятного в том замечении, что очередь с той дисциплиной потребует переписать механизм тасков? V>Это попытка замылить суть вопроса или что?
От критиков ConcurrentQueue не требуется переписать механизм тасков. Если очередь плоха сама по себе — то её можно заменить на ту очередь, которая хорошая сама по себе.
То, что в реализации механизма тасков используется не лучшая реализация очереди для механизма тасков — ортогональный вопрос.
V>Альтернативные lock-free очереди с дисциплиной многие-ко-многим на этом сайте тоже публиковались неоднократно, только при чём тут они, если эта дисциплина банально не нужна в деле огранизаций очередей к конкретным потокам?
Ну, раз они публиковались, то наверняка можно привести на них ссылку. Ну, и убедительно продемонстрировать разницу между "плохим" вариантом и "хорошим" вариантом.
Без этого вся дискуссия — споры футбольных фанатов.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[67]: MS забило на дотнет. Питону - да, сишарпу - нет?
V>Т.е., тебе пока требуется "просто локальность", а в ней разница в 64 байта или 1кб практически отсутствует в разогретом кеше.
Нужен эксперимент.
V>Я не вижу на графиках объезжания на малых объемах данных, но ты утверждаешь обратное.
Надо внимательно смотреть:
V>Это с большой копипастой. V>Я бы для простоты сделал на виртуальных методах или if-ах с последующим разбоксированием.
Не понимаю смысл.
V>Та граница должна будет пересечься и у тебя в каком-то месте.
Ну, вот другое расположение данных. Более кучное.
V>Можно было бы повторить замеры с предварительным full GC после наполнения дерева.
Можно. Почему бы и нет. Сделайте форк да повторите.
V>Обрабатываются по-факту на один уровень косвенности, если содержимое целевого слота памяти независима от текущих вычислений.
Ну так оно ж зависит. Мы же пойдём в неизвестного заранее ребёнка.
V>Но в дотнетной реализации именно это?
Повторюсь: есть подозрение, что в дотнетной реализации срабатывает tailcall. Я её не дизассемблировал — может там вообще вызова нет.
Ну, то есть руками-то я и её могу переписать в такой же цикл, который был у меня в декабре прошлого года.
V>При повороте дочерний узел заменяет собой родительский узел.
Какой именно из дочерних узлов?
V>А у тебя при росте вложенности потребуется перестроить всё дерево, насколько я сейчас понял.
Нет конечно. Рост вложенности — это split, он очень простой. порождаются ровно три узла, независимо от глубины дерева. Это же B-tree, они все работают одинаково.
V>Не только... V>В мутабельном B+ дереве легко последовательно обойти хранящиеся значения (один из основных кейзов для списка), т.к. все листья соеденены в связанный список.
V>В иммутабельном виде этой функциональности нет, насколько я понимаю, поэтому обход достаточно дорогой.
Обход я ещё не оптимизировал; но там скорее всего тоже всё будет не намного дороже. Прямо сейчас итератор сделан тупо через _list[_position], то есть шаг итерации ~ O(log(N)). Можно сделать на immutable stack за O(1).
V>Попробуй опять с гомогенными узлами. V>Там никакая рекурсия не нужна, вирутальность на верхнем уровне тоже, просто сдвигаешься в цикле до листового узла.
Ещё раз: этот код уже есть. Можно посмотреть на версию от 28 декабря 2020.
V>Причём, твой узел заведомо "знает", ссылается ли он на листья или ветки, это один флаг. V>Затем можно приводить ссылку на дочерний узел через Unsafe.As<T>(Object).
Ну разве что.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.