Здравствуйте, Sinclair, Вы писали:
S>Ух ты! Резкий поворот: только что мы говорили о выразительности и объёме кода, как вдруг перешли к производительности. S>Да, это правда — в дотнете с оптимизацией всё не очень хорошо. Но в этом виноват не Linq — как раз он-то делает всё, что можно, чтобы помочь оптимизатору. S>Основная затычка — невозможность инлайнить делегаты, в которые превращается код на linq to objects. S>Если бы были инлайны — то и копирования можно было бы устранить, т.к. результирующий выхлоп был бы эквивалентен "тупому императивному аналогу".
Не был бы. Потому что правильный императивный код не делал бы не то что копирований, но и даже повторных обращений по предыдущему индексу. Правильный код считал бы всё касающееся конкретной строчке на соответствующей ей итерации цикла, оставляя результат вычисления (например результат count или вообще булев флаг — это уже по вкусу) для следующей итерации во внешней к циклу "глобальной" мутабельной переменной. Именно использование таких вещей, родных для процессора, но противоречащих функциональной парадигме и является характерным признаком императивного кода.
_>>Наверняка там простейшее прямое обращение к данным, в классическом императивном стиле. Собственно иначе и быть не может (и даже не из-за производительности), т.к. lag можно задать динамическое смещение (как и в императивном коде). S>Не всё так просто. С учётом того, что исполнительный механизм работает с "перечисляемыми" источниками, которые умеют делать только GetNext() (то есть эквивалентны IEnumerator из дотнета), и не умеют GetRecordNumber(x), то скорее всего там внутри делается скользящий буфер, в случае одиночного смещения превращающийся в ту самую пару значений.
Тогда у тебя всегда должен быть скользящий буфер размером со всю таблицу, потому как функция lag допускает передачу в качестве параметра смещения произвольного значения (т.е. например из какого-то столбца).