Обновить

Комментарии 17

Потому что в конечном итоге, единственная реальность в нашей профессии — это то, как быстро биты бегут по шине памяти.

Реальность разработчиков ПО заключается в том, насколько дешево и качественно мы решаем проблемы бизнеса. Если стоимость ванбординга нового сотрудника или стоимость дополнительного времени разработчика, потраченного на чтение и вникание в подобный код, выше цены на сервер побольше, то писать код из вашего раздела с С не рентабельно.

Опять таки, это с поправкой на бизнес потребность. Если у бизнеса есть потребность в 100500к рпс, подобные оптимизации становятся оправданнее

да, но я говорю относительно собственных проектов

Довольно крутое пояснение. Так же хотел сказать про распределение задач на разные потоки и ядра. Да, кеш третьего уровня общий, но так же есть отдельный кеш на каждое ядро, первого и второго уровня. И таким образом нагрузку можно уменьшить путем распределения инструкций на разные потоки и ядра, особенно если данные не конфликтуют по кеш линиям.Так же думаю, что все зависит от компилятора, который указывает на дыры в оптимизации или сам оптимизирует код, например может переупорядочивать инструкции, векторизовать циклы и эффективнее работать с памятью. Но при этом, если сами данные организованы плохо, как в примере с ООП и разрозненными объектами, компилятор уже мало что спасет, потому что упрется в задержки памяти и cache miss.Как совет, думаю, что важно учитывать не только многопоточность, но и локальность данных, выравнивание структур, размер кеш линий и доступа к памяти. Тогда и проц, и prefetcher смогут работать максимально эффективно. В этом плане data oriented действительно может дать сильный прирост производительности, особенно в задачах с большими массивами однотипных данных

да, спасибо что добавили! Забыл упомянуть

Все так, но вроде многие признают, что мы платим простотой организации за скорость.
И, как показывает практика, готовы платить.
Единственное стоит не забывать, что иногда платим дорого - ООП или какие то отдельные паттерны возводят в абсолют.

Надо сказать, что абстрактное ООП в вакууме tool agnostic, оно непосредственно не накладывает ограничений ни на организацию данных в памяти, ни на производительность.
Страдают в целом современные реализации.
Тем не менее можно и лучше организовывать данные и в рамках классического ООП, и есть варианты более дружелюбных архитектур типа ECS, которая (если очень грубо прикладывать) есть агентное ООП с анемичными данными. Что плохо для читаемости, но лучше для скорости перекладывания байтов.

Как в таком случае писать бизнес логику ?

Преимущество классов в том что мы можем зашить в них бизнес логику и там же поддерживаем инварианты

Отделяем правильное поведение от неправильного

Как в вашем случае это сделать ?

А если капнуть глубже, то современные ЦП способны читать из L1 в 2 регистра по 64байт выровненных данных за такт, но пока мы используем скаляры все это замедляется до 2х 4 байт за такт. И используем только одну инструкцию на скаляр вместо инструкции на 16х скаляров.

Из статьи можно сделать только один вывод - питон плохо работает на процессоре(каком-то) а си работает хорошо. Мне, все же, кажется что дело в том, что си компилируется нормально и даже если написать на плюсах тот же ООП как в питоне, то через компилятор до проца дойдет вариант ничем не хуже чем на си. Привели бы, хотя бы, пример на питоне как хорошо, и на нем же - как плохо. А то между абстрактным кодом и тем что реально попадает в проц - слишком много вариантов чтобы строить теории как правильно

не совсем, это статья про данные и как удобнее читать процессору, а не про конкретный яп

Если проект устроен так, что с кучей котов приходится делать что-то более или менее одинаковое одновременно, тогда действительно: заводить отдельный объект на каждого кота это порочный подход. Тогда нужно заводить объекты Катавасия и Псарня, в котором будут лежать массивы аттрибутов отдельных тварей. И, скажем, векторизация numpy будет управляться с ними очень быстро.

Подход "каждому животному по объекту" нужен, когда Вы делаете совершенно разные вещи с каждым отдельным животным.

Поэтому то, что Вы хотите сказать - это "не всегда самый напрашивающийся дизайн - самый лучший, и уж точно не всегда - самый оптимальный по производительности".

Даёшь ассемблер!

Я не понял примера... я обычно для таких задач chatGPT прошу поменять значения. Делов то, зачем тут ваш Си? LLM как интерпретатор 10/10. Ну или хотя бы эксель.

Ps на сколько я знаю компиляторы умеют такое оптимизировать. Но Змею обидеть может каждый.

Я не про язык говорил...

Так как, типZooData в данном случае теперь один на весь модуль не имеет смысла передавать его в функции по указателю. Хоанить его лучше в секции данных в статической памяти. Ведь нужен всего 1 экземпляр данной структуры. При этом большинсиво функций обработчиков можно заставить работать тодько с элементарными скалярными типами, что без дженериков позволит им работать с разными типами структур. Например функцию update_positions() можно переписать следующим образом:

// функция движения

void update_positions(int *box, int * y, int count ) { // Процессор ликует: данные лежат в памяти ровной линией. // Пока он считает x[0], контроллер памяти уже подтягивает x[1...15] в кэш. for (int i = 0; i < count; i++) { x[i] += 1.0f; y[i] += 1.0f; }}

Вызов: update_positions(zoo->x, zoo->y, zoo->count);

А где в с-реализауии мяв и гав?

вы изобрели геймдев) там это называется entity component system, который как раз решает проблему эффективной работы со стейтом.

И я в целом согласен, потому что навыки классификации и структурирования 99% разработчиков оставляют желать лучшего. И лучше бы им освоить хлеб с маслом, гонять структуры данных по процедурам и не заниматься ерундой.

Я думаю именно поэтому go такой популярный. ( я вообще рубист)

я не изобретал а показал принцип, да go популярен из за слайсов(данные лежат очень плотно), быстроты, горутин(потоки на атомарных инструкциях, с малыми плотными буферами)

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации