Re[116]: Мнение: объектно-ориентированное программирование —
От: alex_public  
Дата: 15.11.19 10:28
Оценка:
Здравствуйте, Sinclair, Вы писали:

_>>Тут на самом деле не всё так просто — надо чтобы компилятор мог гарантированно видеть неизменность переменной "a" внутри цикла. Например в C++ компилятор проводит эту оптимизацию для любых пользовательских типов без всяких модификаторов чистоты. Однако при этом в некоторых специфических случаях она не срабатывает, т.к. компилятор видит потенциальную возможность изменения переменной (хотя на самом деле никаких изменений естественно нет).

S>Основной инструмент, которым пользуется компилятор C++ — это инлайнинг.
S>А дальше — строим SSA-форму, в которой видно, что и где изменяется, и что остаётся инвариантом.

Это да. Я просто уточнил, что вот не всегда он может это корректно определить. В большинстве случаев может, но иногда ошибается.

_>>Так что лучше сразу писать for(int i=0, е=a.GetLength(); i<е; i++), ну или использовать range for, которые транслируется (во всяком случае в C++) как раз в такую конструкцию.

S>Для кого лучше? Например, на C# такой код для встроенных массивов — явная пессимизация. Потому что JIT умеет распознавать паттерн i<a.Count и устраняет проверки границ. А паттерн i<e требует значительно более длинного пути для доказательства невыхода за границы, поэтому проверки будут оставлены.

Ну я то писал про C++. Забавно, что в C# ситуация обратная. Кстати, а в какой код транслируется range for в C#? )

_>>P.S. Если вдруг кто-то думает, что оптимизация выше — это какая то непринципиальная ерунда с экономией пары процессорных тиков, то это совсем не так. Например если мы всё же используем запись цикла в первом варианте и оптимизация с a.GetLength не пройдёт, то это автоматически заблокирует нам автовекторизацию этого цикла. А это уже может быть реальным провалом в быстродействие в десятки раз.

S>Ну вот в том-то и дело: декларация a.GetLength() как pure означает, что она не меняет мир — значит и a остаётся неизменной, поэтому можно оптимизировать всё.

Не значит. Если в теле цикла есть другой (модифицирующий) вызов a. Вот в случае константного a всё однозначно. А когда константности нет, то компилятор должен сам отслеживать и не всегда у него это удаётся верно.

Причём ещё нюанс: нам не обязательно требовать именно чистоты функций, вызываемых в теле цикла. Главное чтобы они не меняли a (т.е. если вдруг у a есть функция, печатающая некую отладочную информацию в консоль, то это не должно помешать такой оптимизации).
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.