Пример оптимизации цикла на С#

Многие любят валить вину за то, что их код медленно работает, на .Net Framework. А между тем во многих случаях ситуацию можно исправить поменяв пару строк кода.

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

Вначале пару слов о границах цикла. Хотя в первой версии фреймворка и были какие-то проблемы с функцией Length, то сейчас все хорошо. Главное, чтоб это не была какая-нибудь хитрая функция, которая выполняется на каждой итерации цикла и замедляет его в несколько раз.

for (i=0; i<Data.Length; i++)
{
    //Обработка
}

Я вообще использую следующую конструкцию, так как цикл распараллелен на несколько ядер (пост):

int i1 = GetFirstIndex();
int i2 = GetLastIndex();
for (i=i1; i<=i2; i++)
{
    //Обработка
}

Далее за границы цикла стоит по возможности вынести все операции по выделению памяти. Кроме того при вызове функций внутри цикла, по возможности нельзя дублировать данные, особенно массивы.
Пример плохого кода:

int i1 = GetFirstIndex();
int i2 = GetLastIndex();
for (i=i1; i<=i2; i+=3)
{
    //Обработка
           double[] rgb = new double[3];
           rgb[0] = Data[i];
           rgb[1] = Data[i+1];
           rgb[2] = Data[i+2];

           double hsl[] = ConvertRGBtoHSL(rgb);

           ResultData[i/3] = hsl[2];
}

double[] ConvertRGBtoHSL(double[] rgb)
{
      double[] hsl = new double[3];
     
      //Конвертация
     
      return hsl;
}

Что я сделал, чтоб оптимизировать этот код: вынес объявление переменных за границы цикла, отказался от передачи массивов по значению, использовал ref для передачи ссылок на рабочие данные.

int i1 = GetFirstIndex();
int i2 = GetLastIndex();

double r = 0;
double g = 0;
double b = 0;
double h = 0;
double s = 0;
double l = 0;

for (i=i1; i<=i2; i+=3)
{
    //Обработка          
           r = Data[i];
           g = Data[i+1];
           b = Data[i+2];

           ConvertRGBtoHSL(r,g,b,ref h, ref s, ref l);

           ResultData[i/3] = l;
}

void ConvertRGBtoHSL(double r, double g, double b, ref double h, ref double s, ref double l)
{      
      //Конвертация
}

Как видно мало что кардинально изменилось, однако, такой код работает у меня раза в два быстрее. Наверняка данный код можно еще более оптимизировать, поэтому если кто то может предложить еще какие-то методы оптимизации, то прошу изложить их в комментариях.

  • Наткнулся на ваш блог, искал инфу по отрисовке геометрических изображений через WPF. Было приятно почитать материалы, пишите еще!

  • 私はこの悪魔のようなうつ病治療と20年間苦闘しました。はじめの10年は一人でうつ病そしてもう10年はうつ病あるドクうつ病ターと共にうつ病に立ち向かっうつ病たと言っていいでしょう。それはあまりにうつ病長く、辛いうつ病治療の経験でした。しかし、その時間は私に、うつ病に対する深い知恵とうつ病の対処法、そして不屈の勇気うつ病を与えてくれたのです。そして、うつ病にさよならしてください。