Array.Copy () быстрее, чем для цикла, для двумерных массивов? - PullRequest
6 голосов
/ 20 сентября 2011

Я недавно изменился

        this.FieldValues = new object[2, fieldValues.GetUpperBound(1) + 1];
        for (int i = 0; i < FieldCount; i++)            
        {
            this.FieldValues[Current, i] = fieldValues[Current, i];
            this.FieldValues[Original, i] = fieldValues[Original, i];
        }

до

        FieldValues = new object[2, fieldValues.GetLength(1)];
        Array.Copy(fieldValues, FieldValues, FieldValues.Length); 

Где значения Current и Original являются константами 0 и 1 соответственно. FieldValues ​​- это поле, а fieldValues ​​- это параметр.

В месте, где я его использовал, версия Array.Copy () оказалась быстрее. Но другой разработчик говорит, что он рассчитал цикл for на Array.Copy () в отдельной программе и нашел цикл for быстрее.

Возможно ли, что Array.Copy () действительно не быстрее? Я думал, что он должен был быть супер-оптимизирован!

Ответы [ 3 ]

7 голосов
/ 17 ноября 2011

По своему опыту я обнаружил, что не могу доверять своей интуиции ни в чем, когда дело касается производительности.Следовательно, я держу в руках быстрое приложение для тестирования производительности (которое я называю «StupidPerformanceTricks»), которое я использую для тестирования этих сценариев.Это бесценно, так как я сделал много удивительных и нелогичных открытий об уловках производительности.Также важно помнить о том, что приложение для тестирования следует запускать в режиме выпуска без подключенного отладчика, так как в противном случае вы не получите JIT-оптимизацию, и эти оптимизации могут иметь существенное значение: метод A может быть медленнее, чем метод B в режиме отладки,но значительно быстрее в режиме выпуска с оптимизированным кодом.

Тем не менее, в целом мой собственный опыт тестирования показывает, что если ваш массив содержит <~ 32 элементов, вы получите лучшую производительность, выполнив свой собственный цикл копирования.- предположительно, потому что у вас нет накладных расходов на вызов метода, что может быть значительным.Однако, если цикл больше ~ 32 элементов, вы получите лучшую производительность с помощью Array.Copy ().(Если вы копируете целые числа, числа с плавающей запятой или другие подобные вещи, вы можете также изучить Buffer.BlockCopy (), который на ~ 10% быстрее, чем Array.Copy () для небольших массивов.) </p>

Но все это говорит о том, что реальный ответ таков: «Напишите свои собственные тесты, которые максимально точно соответствуют этим точным альтернативам, оберните их каждый циклом, дайте циклу достаточно итераций, чтобы он пережевал не менее 2-3 секунд.CPU, а затем сравните альтернативы самостоятельно. "

4 голосов
/ 20 сентября 2011

Как работает .Net под капотом, я бы предположил, что в оптимизированной ситуации Array.Copy позволит избежать проверки границ.

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

Вы можете изменить это поведение, но, как правило, вы экономите не так много.Если вы не находитесь в жестко выполненном внутреннем цикле, где каждая миллисекунда имеет значение, т.е.*

Я думаю, что проверка границ дает разные результаты для вас.

0 голосов
/ 20 сентября 2011

В вашем конкретном примере есть фактор, который может (в теории) означать, что для цикла быстрее.

Array.Copy - это операция O (n), в то время как ваш цикл for равен O (n / 2), где n - это общий размер вашей матрицы.

Array.Copy необходимо зациклить все элементы в ваших двухмассив из-за того, что:

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...