Самое важное правило - это все теория, пока вы не профилируете. Я не верю в тех, кто настаивает на том, что профилирование - это все (без какой-либо теории вы не лучше, чем Культист-грузчик, который кладет кокосы на уши и ждет прибытия самолета), но ваша теория всегда может быть неправильной или неполной, поэтому профилирование имеет решающее значение.
Как правило, мы хотим, чтобы внутреннее сканирование выполнялось горизонтально (с точки зрения массива, а не изображения, хотя для большинства форматов это одно и то же). Причина в том, что с массивом вроде:
00 01 02 03 04 05 06 07 08 09
10 11 12 13 14 15 16 17 18 19
20 21 22 23 24 25 26 27 28 29
Это будет выложено как:
00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
Вы хотите сканировать по смежным блокам, которые можно загружать в кеши ЦП и затем использовать целиком, а не сканировать от блока к блоку и требовать регулярного изменения содержимого кэша ЦП.
Это еще более важно, если вы попытаетесь распараллелить алгоритм. Вы хотите, чтобы каждый поток имел дело со своими собственными смежными блоками памяти на протяжении как ввода, так и вывода, а не только страдал, как однопоточный код, с плохой частотой попаданий в кэш, но также вызывал загрязнение буферов друг друга и нужно освежить. В этом может быть разница между распараллеливанием, приводящим к увеличению скорости, и распараллеливанием, фактически замедляющим вещи.
Другая вещь - это разница между 2-мерным массивом byte[,]
, а не массивом массивов byte[][]
, и ваш комментарий в вашем вопросе "array [y] [x]" заставляет меня задуматься, возможно, вы используете , С первым для получения arr [1,2] логика:
- Проверить границы
- Расчет позиции (простая быстрая арифметика)
- Получить значение.
С последним логика:
- Проверить границы
- Получить массив через указатель.
- Проверить границы
- Получить значение.
Существует также менее хорошая частота попадания в кэш-память. Последний имеет преимущества, когда нужны «зубчатые» конструкции, но здесь это не так. 2D почти всегда быстрее, чем массив массивов.
Вещи, которые я не вижу, которые могут помочь, но я бы обязательно попробовал их в вашей ситуации:
Вы можете получить импульс от выполнения своей 1d <=> 2d логики. Имейте одномерный массив, где idx = y * width + x. Это не должно иметь заметного значения, но стоит попробовать.
Оптимизации действительно пытаются поднять вызовы на .Length
и пропустить ненужную проверку границ, поэтому вы можете обнаружить, что подъем вручную и переключение на арифметику указателей ничего не дает, но в случае, когда вам действительно нужно сократить время это, безусловно, стоит профилировать.
Наконец-то. Вы рассказали, как быстро ваш код сканирует массив и ничего не делает? Возможно, другая часть кода - это настоящее узкое место, и вы исправляете не то.