Здравствуйте, vdimas, Вы писали:
V>Собсно, вообще таких алгоритмов мало, которые можно выразить в дотнете для value и ref-типов в генериках и они будут корректно работать в обоих случаях. Я одно время на этом собаку съел, в поисках классов таких алгоритмов, которые, таки, работают в обоих случаях и в попытках сформулировать ограничения на такие алгоритмы.
Ок, допустим ты на adaptors::indirected думаешь, но как тогда в твоей картине мира объясняется более чем стократное торможение на list<int>? — там никакого adaptors::indirected.
Ладно, вместо тысячи слов — встречайте её могущество копипаста без boost'а. Соотношения получились примерно те же самые
using System;
using System.Collections.Generic;
internal class GenericEqualityComparer<T> : EqualityComparer<T> where T : IEquatable<T>
{
public override bool Equals(T x, T y)
{
if (x != null)
{
if (y != null) return x.Equals(y);
return false;
}
if (y != null) return false;
return true;
}
public override int GetHashCode(T obj) => obj?.GetHashCode() ?? 0;
// ...
}
Q>>Пример был про то, как вызывается метод констрейнта у экземпляра типа
V>Никак он не вызывается. V>x.Equals(y) — это метод базового Object
internal struct Foo : IEquatable<Foo>
{
public bool Equals(Foo other)
{
Console.WriteLine("Equals(Foo other)");
return true;
}
public override bool Equals(object obj)
{
Console.WriteLine("Equals(object obj)");
return true;
}
public override int GetHashCode() => 0;
}
internal static class Program
{
private static void Main()
{
var comparer = new GenericEqualityComparer<Foo>();
var x = new Foo();
var y = new Foo();
var equal = comparer.Equals(x, y);
Console.WriteLine(equal);
}
}
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Ладно, вместо тысячи слов — встречайте её могущество копипаста без boost'а. Соотношения получились примерно те же самые
1) По твоему тесту:
Во-первых, как я понял, ты пытаешься измерить задержки из-за cache-miss с помощью listа. Думаю, что это не очень хороший подоход, т.к. элементы list могут быть расположены в памяти последовательно. В моем же тесте, я точно обращаюсь к элементам в случайном порядке.
Во-вторых, ты измеряешь производительность stl контейнеров, а не процессора.
2) По моему тесту:
В моем измерении тоже были ошибки: я компилировал без оптимизатора, а когда подключил оптимизатор он выкинул весь расчет. В конце поста я приведу для конкретности последний вариант своего кода.
Результаты изменились:
Последовательное сложение с индирекцией оказалось ровно в два раза медленне, чем с индирекцией. Это ожидаемо, т.к. выполняется две инструкции, вместо одной.
Сложение со случайным доступом(и вечным cache-miss) оказалось еще в два раза медленнее, чем с последовательным. Это обозначает верхнюю границу эффективности кэша при доступе к данным, и для меня интересно.
Предлагаю на этом результате остановиться, т.к. он меряет именно скорость процессора, а не скорость контейнеров stl. Кстати, только vector<int> оказался по скорости близок к массивам, а в остальных вариантах при одном, по сути, алгоритме твоя программа с stl, действительно, работает на порядки медленнее моей при одном размере массива(что удивило даже меня).
Относительно причин задержек Java/C# vs C++ думаю, что лишний код присущ JIT-компиляторам, и лишние индирекции часть этой проблемы. Однако, программируя на C++, очень редко есть смысл заботиться об индирекции, т.к. далеко не все функции в программе занимают значительное время. И алгоритм работы(особенно не относящийся к вычислительным) почти никогда не состоит из одной инструкции сложения чисел, поэтому обращения к памяти вносят меньший вклад во время выполнения, чем в этих синтетических тестах. Поэтому для меня лично кэш-миссы и индирекции недостаточная причина всегда использовать move-семантику для каждого вектора больших объектов(т.к. это слишком мелкая микрооптимизация, усложняющая код) и все же буду использовать указатели, а при тяжелых вычислениях я постараюсь обойтись без stl. Вообще, C++ быстр сам по себе и программа будет работать быстрее, чем C#/Java, в любом варианте.
Привожу мой тест в последнем варианте:
#include <iostream>
#include <chrono>
#include <stdlib.h>
using namespace std;
#define SIZE 4000*1000
int *array;
int *map1, *map2;
int test(int *map)
{
int sum = 0;
for (int i=0; i<SIZE; i++)
sum += array[map[i]];
return sum;
}
int test0()
{
int sum = 0;
for (int i=0; i<SIZE; i++)
sum += array[i];
return sum;
}
int main()
{
srand(time(0));
array = new int[SIZE];
map1 = new int[SIZE];
for (int i=0;i<SIZE;i++) {
map1[i] = i;
array[i] = random();
}
map2 = new int[SIZE];
for (int i=0;i<SIZE;i++)
map2[i] = random()%SIZE;
auto start0 = std::chrono::high_resolution_clock::now();
int r = test0();
auto finish0 = std::chrono::high_resolution_clock::now();
cout << r << ":" <<std::chrono::duration_cast<std::chrono::nanoseconds>(finish0-start0).count() << "ns\n";
auto start1 = std::chrono::high_resolution_clock::now();
r = test(map1);
auto finish1 = std::chrono::high_resolution_clock::now();
cout << r << ":" << std::chrono::duration_cast<std::chrono::nanoseconds>(finish1-start1).count() << "ns\n";
auto start2 = std::chrono::high_resolution_clock::now();
r = test(map2);
auto finish2 = std::chrono::high_resolution_clock::now();
cout << r << ":" << std::chrono::duration_cast<std::chrono::nanoseconds>(finish2-start2).count() << "ns\n";
}
У сложных вещей обычно есть и хорошие, и плохие аспекты.
Берегите Родину, мать вашу. (ДДТ)
Здравствуйте, Serginio1, Вы писали:
S> Это же все можно делать и в C# это же Func<X,Y>
Ну, дык, статически диспетчеризируемую полиморфную операцию сравнения не сделать.
Только динамически через экземпляр IComparer<T> или через ручной copy&paste с целью ad-hoc полиморфизма.
Причем, там же рядом я писал:
Понятно, что x => x.Y выглядит тривиально, это был лишь пример. В общем случае "оно" может быть не тривиальным, т.к. именно под нетривиальные объемы кода пишут те самые шаблоны "многоразового применения" — в этом их фишка.
Это всё к тому, что твой пример с copy&paste вот этого:
where(x => x > q)
в общем случае является плохой практикой.
Но язык позволяет только такую.
И да, как и в адрес Qbit86 я умудрился ответить на все вопросы намного раньше, чем их задали. ))
И ладно бы, тебе я копирую с соседней подветки, а вот означенному персонажу я заранее отвечал в этой же, предугадывая его т.н. "логику".
И всё-равно там отставание по фазе дважды случилось...
разную семантику для value vs ref типов — вот уж где будет бесшовный рефакторинг при замене одного на другое
Я писал свои экземпляры генерик-коллекций с уменьшенной, в сравнении со стандартной, косвенностью и понаблюдал массу всех этих светошумовых эффектов из-за такой разницы.
И что характерно, что в терминах JIT-машинки управляемая ссылка на объект и управляемая ссылка на поле объекта или ref/out-параметр передаваемой через аргументы структуры — всё это обслуживается одинаково, т.е. под это генерится идентичный код, а GC затем прекрасно умеет отличить ref-ссылку на поле объекта в куче от такой же ссылки на экземпляр на стеке. Но, в терминах языка C#, ref/out value-type и переменная ссылочного ref-типа это РАЗНЫЕ типы ссылок, о как! ))
Т.е., там где в С++ алгоритму глубоко до фени, где создан объект (на куче, на стеке или в виде поля другого объекта), в дотнете в этом же месте есть исскуственно введеная непреодолимая разница на уровне типов. А разница семантики генериков для value-типов и для ref-типов, это как разница м/у указателем на тип и самим типом, т.е. разница, казалось бы, катастрофическая. Но тут ровно наоборот — код при этом должен "выглядеть" одинаково, ы-ы-ы много раз. ))
Не так вот эта чушь: «Никак он не вызывается. x.Equals(y) — это метод базового Object», в ответ на «Пример был про то, как вызывается метод констрейнта у экземпляра типа».
Приведённый код самодостаточен, его можно скопировать в IDE и запустить: http://ideone.com/9tlRqT
Любой может проверить, что вызывается, конечно, метод, реализующий интерфейс `IEquatable<T>`, а не «метод базового Object».
Значит, такое владение предметом.» Это ведь не голословное утверждение, а результат прямой и непосредственной проверки твоего заявления.
Ты хамишь и пытаешься самоутвердиться, повторяя какую-то чушь, о том как ты что-то там предугадал, а оппонент не прочитал твои мысли.
Ты хвастаешься, что якобы съел собаку в дженериках, но демонстрируешь непонимание самых базовых вещей, без знания которых нельзя пройти собеседование даже на джуниора.
Здравствуйте, Qbit86, Вы писали:
V>>Что не так-то? Q>Не так вот эта чушь: «Никак он не вызывается. x.Equals(y) — это метод базового Object», в ответ на «Пример был про то, как вызывается метод констрейнта у экземпляра типа».
У тебя по ссылке 4 места с x.Equals(y), например такое:
internal sealed class ObjectEqualityComparer<T>: EqualityComparer<T>
{
[Pure]
public override bool Equals(T x, T y) {
if (x != null) {
if (y != null) return x.Equals(y);
return false;
}
if (y != null) return false;
return true;
}
Q>Приведённый код самодостаточен, его можно скопировать в IDE и запустить
Ну запусти и убедись, вызывается метод класса Object.
Q>Ты хамишь и пытаешься самоутвердиться
На тебе самоутверждаться малость не спортивно.
Q>повторяя какую-то чушь, о том как ты что-то там предугадал, а оппонент не прочитал твои мысли.
Пока что ты банально написанное не можешь прочесть и дважды умудрился спросить меня о том, что я тебе уже заранее ответил.
Какие там в опу "мысли предугадать"...
Q>Ты хвастаешься, что якобы съел собаку в дженериках, но демонстрируешь непонимание самых базовых вещей
Ты так и не показал моего непонимания. Ну вот я тебе дал снипет по твоей ссылке.
Выкручивайся.
Q>без знания которых нельзя пройти собеседование даже на джуниора.
Кисо обиделось?
А как же я тут тебе заранее написал:
Даже если у тебя будет констрейн where T : IBarable<T> — я уверен, ты сам сможешь доработать мой сниппет до такого сценария.
Ну вот и третья задержка по фазе.
Стабильность, признак мастерства?
Q>Этот глумильщик сломался, несите следующего.
А не, просто пафос. Следом будет очередное пффф. ))
Здравствуйте, vdimas, Вы писали:
Q>>Не так вот эта чушь: «Никак он не вызывается. x.Equals(y) — это метод базового Object», в ответ на «Пример был про то, как вызывается метод констрейнта у экземпляра типа».
V>У тебя по ссылке 4 места с x.Equals(y), например такое: V>
internal sealed class ObjectEqualityComparer<T>: EqualityComparer<T>
А почему бы мне не было дать тебе понять, что ты явно поторопился рассуждать о каких-то там юниорах, после вот этого:
Даже если у тебя будет констрейн where T : IBarable<T> — я уверен, ты сам сможешь доработать мой сниппет до такого сценария.
Т.е., следующий твой шаг в рассуждениях от T к ISomeInterface<T> был слишком очевидным на тот момент, что я заранее попытался тебя попросить не рвать жилы в эту сторону, бо там там преимуществ перед С++ тоже не найдёшь, а, ровно наоборот — обнять и плакать. ))
Ан нет, до тебя даже такой толстый намёк не дошёл.
internalclass GenericEqualityComparer<T>: EqualityComparer<T> where T: IEquatable<T>
Ну и?
Ты ведь вызвался оспорить вот это:
Собсно, вообще таких алгоритмов мало, которые можно выразить в дотнете для value и ref-типов в генериках и они будут корректно работать в обоих случаях.
Ну как, получилось?
Разве ты еще не увидел, что твой пример был неудачный? Что сам вот этот код — это workaround вокруг тривиальных в других языках вещей?
Что это не целевой ни разу код, а тупо костыль, "восполнение пробела"?
Что базовые типы засоряются реализацией тонны методов прямо в метаинформации и в байт-коде?
И что выделенное ключевое слово — это ошибка дизайна?
Что надо было дать некий struct ValueTypeComparer<T> как минимум, потому что иначе ЛЮБОЕ сравнение, сцуко, всё-равно будет происходить через метод интерфейса, т.е. никакой нафик параметрический полиморфизм толком не будет работать — будет голая динамика плюс эдакий синтаксический сахар.
Что даже указанный тобой "типизированный" вызов x.Equals(y) происходит внутри генерик-метода, реализующего интерфейс? (что ты скромно делаешь вид, что не замечаешь или подзабыл, угу)
Ну и возвращаясь к нашим баранам. Вот, если быть честным с самим собой (забыть на минуту о запале форумного боя), ты что, ДЕЙСТВИТЕЛЬНО не согласен с процитированным (последнее на жёлтеньком)?
А то ж, если будешь продолжать упираться, то уже мне придется шутить о соответствии хотя бы джуниору, только, в отличие от, с полным основанием-то. ))
Не хочешь на досуге помедитировать над вот этой сладкойпарочкой, кста? Очень рекомендую к ознакомлению. Это именно то, как решаются реальные проблемы (С) при наличии, казалось бы, рекламируемого тобой якобы "параметрического полиморфизма" в C#. Весь код по ссылке именно таков как раз от того, что дотнетный якобы "параметрический полиморфизм" не в состоянии разресолвится статически, исключив динамику интерфейсных вызовов, потому что не реализует статически даже полиморфизм 1-го ранга, в отличие от того же Хаскеля, который ровно в этих же сценариях ресолвит всё статически. В общем, добро пожаловать в реальный мир, Нео.
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, Qbit86, Вы писали:
V>>>Что не так-то? Q>>Не так вот эта чушь: «Никак он не вызывается. x.Equals(y) — это метод базового Object», в ответ на «Пример был про то, как вызывается метод констрейнта у экземпляра типа».
V>У тебя по ссылке 4 места с x.Equals(y), например такое: V>
V>internal sealed class ObjectEqualityComparer<T>: EqualityComparer<T>
V> {
V> [Pure]
V> public override bool Equals(T x, T y) {
V> if (x != null) {
V> if (y != null) return x.Equals(y);
V> return false;
V> }
V> if (y != null) return false;
V> return true;
V> }
V>
Q>>Приведённый код самодостаточен, его можно скопировать в IDE и запустить
V>Ну запусти и убедись, вызывается метод класса Object.
про `GenericEqualityComparer<T>`: V>Который не умеет вызывать operator==? ))
А зачем его вызывать? Алгоритмы и коллекции стандартной библиотеки работают через компараторы, они не используют `operator ==`. Ты и этого не знал? Это легко проверить: для кастомного класса или структуры определи `operator ==` бросающим исключение:
using System;
using System.Collections.Generic;
internal struct/* or sealed class */ IntWrapper : IEquatable<IntWrapper>
{
public IntWrapper(int i)
{
Value = i;
}
public int Value { get; }
public bool Equals(IntWrapper other) => Value == other.Value;
public override int GetHashCode() => Value.GetHashCode();
public override bool Equals(object obj) { throw new NotSupportedException(); }
public static bool operator ==(IntWrapper left, IntWrapper right) { throw new NotSupportedException(); }
public static bool operator !=(IntWrapper left, IntWrapper right) { throw new NotSupportedException(); }
}
internal static partial class Program
{
private static void Main()
{
var d = new Dictionary<IntWrapper, string>
{
{ new IntWrapper(42), "Hello" },
{ new IntWrapper(1729), "World" },
};
var s = d[new IntWrapper(1729)];
Console.WriteLine(s);
}
}
Заодно убедишься, что `bool Equals(object obj) { throw new NotSupportedException(); }` тоже не вызывается.
V>Т.е., следующий твой шаг в рассуждениях от T к ISomeInterface<T> был слишком очевидным на тот момент... Ан нет, до тебя даже такой толстый намёк не дошёл. :xz:
Всем очевидно, что приводить аргументы в защиту твоей позиции — это твоя забота, а не оппонента. Если уж предугадываешь «слишком очевидные» шаги — продолжай это делать. Расписывай дальше, какими хаками обмазываться в плюсах и что к чему кастить, если в функцию передаётся не `T *`, а `std::vector<T>`, `std::function<T()>`, `std::function<void(T)>` и так далее.
V>Ты ведь вызвался оспорить вот это: V>
V>Собсно, вообще таких алгоритмов мало, которые можно выразить в дотнете для value и ref-типов в генериках и они будут корректно работать в обоих случаях.
V>Ну как, получилось? :facepalm:
Конечно, пример с `IEquotable<T>` это наглядно показывает. В этом примере http://ideone.com/9tlRqT сделай Foo классом, а не структурой — всё будет «корректно работать в обоих случаях».
V>Разве ты еще не увидел, что твой пример был неудачный? V>Что надо было дать некий struct ValueTypeComparer<T>
Ты просто не понял примера. Он был не про компарер и его использование. А про использование внутри него `IEquatable<T>`: не через `...some-method...(IEquatable<T> x, IEquatable<T> y)`, а через `...some-method...(T x, T y) ... where T : IEquatable<T>`:
public interface IEquatable<T>
{
bool Equals(T other);
}
internal ...some-class...<T> ... where T : IEquatable<T>
{
public override bool ...some-method...(T x, T y)
{
if (x != null)
{
if (y != null) returnx.Equals(y);
return false;
}
if (y != null) return false;
return true;
}
///...
}
V>Что даже указанный тобой "типизированный" вызов x.Equals(y) происходит внутри генерик-метода, реализующего интерфейс? (что ты скромно делаешь вид, что не замечаешь или подзабыл, угу)
В примере это вообще не важно, вызывающий «генерик-метод» может ничего не реализовывать, а быть сам по себе. Тут важно, что некий алгоритм выражается не напрямую через `IEquatable<T>`, а выражается в терминах `T : IEquatable<T>`, что позволяет передавать ему структуры без боксинга.
V>Ну и возвращаясь к нашим баранам. Вот, если быть честным с самим собой (забыть на минуту о запале форумного боя), ты что, ДЕЙСТВИТЕЛЬНО не согласен с процитированным (последнее на жёлтеньком)?
Да, расскажи, что помешает в этом примере http://ideone.com/9tlRqT сделать `Foo` не структурой а классом?
V>А то ж, если будешь продолжать упираться, то уже мне придется шутить о соответствии хотя бы джуниору, только, в отличие от, с полным основанием-то. ))
Твоё утверждение «Никак он не вызывается. x.Equals(y) — это метод базового Object» наглядно свидетельствует о том, что ты совершенно не понимаешь происходящего. Вопрос вполне можно рекомендовать к включению в собеседование на должность джуниора, чтобы сразу отсеевать тех, кто не обладает минимальной компетенцией.
Глаза у меня добрые, но рубашка — смирительная!
Re[24]: Visual C# vs C++. Надо сравнить перспективы.
Здравствуйте, itslave, Вы писали:
_>>Нуу не стоит путать базовые принципы и недоработку реализации библиотечной функции под одной из платформ. ) I>Ну знаешь ли, и .NET тоже тогда кроссплатформенный. В базовых принципах. Ога, с недоработками реализации библиотечных функций одной из платформ.
Нуу смотри. Понятно, что сами языки в большинстве своём (не трогаем Ассемблер и т.п.) не зависят от платформы. Соответственно реальная кроссплатформенность определяется наличием компиляторов и стандартных библиотек под нужные платформы.
В случае C++ мы имеем наличие компиляторов и библиотек наверное под все существующие платформы (и нужные и экзотику). Но на отдельных платформах отдельная библиотечная функция в специфической ситуации может себя вести некорректно (не по стандарту), вследствие криворукости местных кодеров.
В случае C# мы просто имеем отсутствие этих самых библиотек для всех платформ кроме винды.
На мой взгляд это весьма разный уровень кроссплатформенности. )))
Re[25]: Visual C# vs C++. Надо сравнить перспективы.
Здравствуйте, Serginio1, Вы писали:
_>>В случае C# мы просто имеем отсутствие этих самых библиотек для всех платформ кроме винды. S>А как же .Net Core?
А ее даже под виндой испрльзовать стремно. Кстати, что там с поддежкой winxp или iot девайсов?
Если у Вас нет паранойи, то это еще не значит, что они за Вами не следят.
Re[26]: Visual C# vs C++. Надо сравнить перспективы.
Здравствуйте, Serginio1, Вы писали:
_>>В случае C# мы просто имеем отсутствие этих самых библиотек для всех платформ кроме винды. S>А как же .Net Core?
Хосспади, вы про этот долбаный великолепный .Net Core пишете в каждом посте.
Нет его по факту нигде, и не факт, что вообще будет. А если что-то и будет, то по производительности все равно будет хуже, чем С++.
Здравствуйте, lpd, Вы писали:
lpd>В моем измерении тоже были ошибки: я компилировал без оптимизатора, а когда подключил оптимизатор он выкинул весь расчет.
lpd>Последовательное сложение с индирекцией оказалось ровно в два раза медленне, чем с индирекцией. Это ожидаемо, т.к. выполняется две инструкции, вместо одной.
А какие у тебя опции оптимизации? Надеюсь включена автовекторизация? )
lpd>Сложение со случайным доступом(и вечным cache-miss) оказалось еще в два раза медленнее, чем с последовательным. Это обозначает верхнюю границу эффективности кэша при доступе к данным, и для меня интересно.
Ну так "в два раза медленнее" — это вроде вполне не плохой результат, не так ли? )
lpd>Относительно причин задержек Java/C# vs C++ думаю, что лишний код присущ JIT-компиляторам, и лишние индирекции часть этой проблемы.
Причины медленности Java и C# можно принципиально разделись на два типа:
1. Слабый оптимизатор (по историческим причинам ориентации на JIT), не позволяющий делать глубокий инлайнинг и прочие сильные оптимизации. Теоретически это исправимо со временем (хотя с учётом остановившегося роста быстродействия процессоров это будет не так просто для случая JIT), но в данный момент времени это именно так.
2. Принципиальные архитектурные особенности. Такие как ориентация на ссылочные данные (я уже не говорю про так называемый "боксинг"), приводящие к той самой косвенности. Принудительные виртуальные функции. Убогая и никчемная интроспекция времени выполнения (рефлексия), вместо эффективной интроспекции времени компиляции (как например в языке D). И ещё множество подобных, но более узкоспециализированных нюансов, общим для которых является то, что их всех нельзя исправить не переделав платформу с нуля. Точнее в Java существует некий механизм (специальный оптимизатор работающий внутри JVM и изменяющий исполнение кода на основание наблюдения за его предыдущими исполнениями) под названием escape-анализ, который пытается частично исправлять ситуацию с излишней косвенностью (перемещая некоторые данные из кучи в стек) и виртуальными функциями (делая вместо виртуального вызова инлайнинг кода конкретного потомка), но он нормально срабатывает только для некоторых редких случаев и то вероятностно (в зависимости от обрабатываемых данных). Так что в целом можно сказать, что указанные проблемы являются принципиально неисправимыми.
Какой из этих типов тормозов вносит больший вклад зависит конечно же от конкретного кода. Но я сомневаюсь, что в большинстве случаев главной причиной является тип1 (как по сути утверждал тут ты).
lpd>Однако, программируя на C++, очень редко есть смысл заботиться об индирекции, т.к. далеко не все функции в программе занимают значительное время.
Если программировать в стиле нормального современного C++, то ни о чём заботиться и не надо — всё будет происходить автоматически. Кстати, это как раз одно из главных и старейших преимуществ C++, что программа написанная без всяких специальных оптимизаций (но в каноническом стиле) будет при этом исполняться на близких к максимальным уровнях производительности. Но это главную возможность очень легко сломать, если перейти от программирования в стиле канонического C++ к стилю Java (компилятор C++ же легко позволяет и такое, но вот быстродействие в таком случае уже никто обещать не будет).
lpd>Вообще, C++ быстр сам по себе и программа будет работать быстрее, чем C#/Java, в любом варианте.
Здравствуйте, alex_public, Вы писали:
_>Здравствуйте, lpd, Вы писали:
lpd>>Сложение со случайным доступом(и вечным cache-miss) оказалось еще в два раза медленнее, чем с последовательным. Это обозначает верхнюю границу эффективности кэша при доступе к данным, и для меня интересно.
_>Ну так "в два раза медленнее" — это вроде вполне не плохой результат, не так ли? )
Неплохой, однако в типичной серверной/десктопной/системной программе на C++(мы вроде не говорим на вычислениях) редко встречается последовательный доступ к большим векторам, да еще с минимальной обработкой. Ясно, что в редких случаях, вроде обработки запроса из кэша баз данных(например) доступ последовательный, но и там temportal кэширование важнее, чем spatial. Поэтому я бы не сказал, что однозначно всегда лучше хранить в векторе объекты, чем указатели. Т.к. обычно это вопрос архитектуры, или избежания копирования, а не оптимизации кэша. Хотя, случаи разные, — это понятно.
lpd>>Относительно причин задержек Java/C# vs C++ думаю, что лишний код присущ JIT-компиляторам, и лишние индирекции часть этой проблемы.
_>Причины медленности Java и C# можно принципиально разделись на два типа:
_>Какой из этих типов тормозов вносит больший вклад зависит конечно же от конкретного кода. Но я сомневаюсь, что в большинстве случаев главной причиной является тип1 (как по сути утверждал тут ты).
Я не исследовал JVM, но могу предположить, что байт код отличается от внутреннего представления программы компилятором, поэтому он вносит дополнительные сущности, которые потом сложно соптимизировать. Это всего лишь мое предположение. Однако, я думаю, что низкая производительность присуща любому языку, преобразуемому в промежуточный байт-код. Иначе давно бы Java, C# или другой подобный язык догнал по скорости C++(правда, я все равно считал бы, что байт-код по сути является не нужным усложнением).
У сложных вещей обычно есть и хорошие, и плохие аспекты.
Берегите Родину, мать вашу. (ДДТ)
Здравствуйте, lpd, Вы писали: lpd>Сложение со случайным доступом(и вечным cache-miss) оказалось еще в два раза медленнее, чем с последовательным. Это обозначает верхнюю границу эффективности кэша при доступе к данным, и для меня интересно.
Вероятно сильно зависит от железа (проц? размер кэшей ?), но разница может доходить и до порядка: