| >> |
No.28291
>>28287
Давайте по пунктам.
1. -O3 не всегда и не обязательно быстрее -O2. Этот режим использует рискованные оптимизации и городит тупо больше кода, разворачивая и инлайня всё и вся.
2. Указатели - это как правило причина не высокой, а низкой скорости. И под указателями я имею ввиду и переменные типа MyClass в какой-нибудь джаве, питоне, джаваскрипте и почти любом другом языке (да, в них это "безопасные", с запрещённой арифметикой, с гарбадж коллекцией или подсчетом ссылок, но, по сути, всё те же указатели под капотом). Причина низкой скорости кода в огромном числе случаев - банальный cache miss (промах мимо L2 или L3 в CPU). Если нужно прыгнуть по указателю к данным, которые процессор не обрабатывал некоторое время до этого, затем из тех данных взять указатель и еще раз прыгнуть к другим данным, и так 10 раз, то это будет работать так же медленно на C++, как и на C#. И способ защититься от этого, по-максимуму, минимизировать прыжки по указателям, стараться не использовать наследование, особенно с виртуальными методами. Собственно, если у вас есть несколько плоских массивов отдельно друг от друга и вы обращаетесь к ним по указателям, но работаете над ними продолжительное время, и они полностью помещаются в кэш или просто вы работаете с ними последовательно (успевает префетчер), то всё в порядке. Если же у вас миллионы объектов, которые содержат указатели на миллионы объектов, и вы постоянно работаете над разными объектами, для ядер процессора это зал ожидания в аэропорте.
3. Это часто усложняет код, но в критических областях имеет смысл использовать идиому SoA. Об этом говорил, например, всё тот же Майк Эктон >>27940 - "мы даже не говорим о том, чтобы использовать кэш-линии максимально эффективно, но о том, чтобы хотя бы использовать их, а не тратить впустую". Допустим, есть объекты, содержащие много полей. Часто вы проходите по большому числу этих объектов, обрабатывая только одно-два поля. В этом случае, кэш-линии забиваются данными, которые вы просто не используете. Это приводит к тому, что очень много раз процессор запрашивает данные из ОЗУ. Гораздо больше раз, чем мог бы. Это приводит к замедлению кода в десятки и даже сотни раз! И GC или JIT не имеет к этому ни малейшего отношения. Они просто не занимаются тем, как данные организованы в оперативной памяти. Большинство же современных ЯП даже поощряют практику хранения всего по отдельности в памяти. Думайте.
|