Как ускорить вложенные циклы в C # - PullRequest
0 голосов
/ 29 июня 2019

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

  • «Данные» - это растровое изображение серого изображения.
  • «Фильтр» - это матрица [3,3].
  • Максимальные значения "fh" и "fw" равны 3.

Я хочу ускорить этот код.

Я также пытался использовать параллель, но он не работал правильно (ошибка с выходом за пределы).

private float[,] Differentiate(int[,] Data, int[,] Filter)
{
    int i, j, k, l, Fh, Fw;

    Fw = Filter.GetLength(0);
    Fh = Filter.GetLength(1);

    float sum = 0;
    float[,] Output = new float[Width, Height];

    for (i = Fw / 2; i <= (Width - Fw / 2) - 1; i++)
    {
        for (j = Fh / 2; j <= (Height  - Fh / 2) - 1; j++)
        {
            sum=0;

            for(k = -Fw/2; k <= Fw/2; k++)
            {
                for(l = -Fh/2; l <= Fh/2; l++)
                {
                    sum = sum + Data[i+k, j+l] * Filter[Fw/2+k, Fh/2+l];
                }
            }

            Output[i,j] = sum;
        }

    }

    return Output;
}

Ответы [ 2 ]

3 голосов
/ 29 июня 2019

Для параллельного выполнения вам нужно отбросить язык c, как объявление переменной, в начале метода и объявить их в фактической области видимости, чтобы они использовались, чтобы они не были разделены между потоками. Параллельное выполнение этого должно принести некоторую выгоду для производительности, но делать их все ParallerFors не очень хорошая идея, поскольку существует ограничение на количество потоков, которые фактически могут работать параллельно. Я бы попробовал сделать это только с помощью верхнего уровня:

private static float[,] Differentiate(int[,] Data, int[,] Filter)
{
    var Fw = Filter.GetLength(0);
    var Fh = Filter.GetLength(1);

    float[,] Output = new float[Width, Height];

    Parallel.For(Fw / 2, Width - Fw / 2 - 1, (i, state) =>
    {
        for (var j = Fh / 2; j <= (Height - Fh / 2) - 1; j++)
        {
            var sum = 0;
            for (var k = -Fw / 2; k <= Fw / 2; k++)
            {
                for (var l = -Fh / 2; l <= Fh / 2; l++)
                {
                    sum = sum + Data[i + k, j + l] * Filter[Fw / 2 + k, Fh / 2 + l];
                }
            }

            Output[i, j] = sum;
        }
    });
    return Output;
}
2 голосов
/ 29 июня 2019

Это прекрасный пример задачи, в которой использование графического процессора лучше, чем использование процессора.Графический процессор способен выполнять триллионы операций с плавающей запятой в секунду (TFlops), в то время как производительность процессора все еще измеряется в GFlops.Суть в том, что это хорошо, если вы используете SIMD инструкции (Single Instruction Multiple Data).GPU отлично справляется с параллельными данными задачами.Если для разных данных требуются разные инструкции, использование графического процессора не дает никаких преимуществ.

В вашей программе элементы вашего растрового изображения проходят одни и те же вычисления: одни и те же вычисления только с немного разными данными (SIMD!).Так что использование GPU - отличный вариант.Это не будет слишком сложно, потому что с вашими потоками вычислений на GPU не нужно будет обмениваться информацией, и при этом они не будут зависеть от результатов предыдущих итераций (каждый элемент будет обрабатываться другим потоком на GPU).

Вы можете использовать, например, OpenCL для легкого доступа к графическому процессору.Подробнее об OpenCL и использовании графического процессора здесь: https://www.codeproject.com/Articles/502829/GPGPU-image-processing-basics-using-OpenCL-NET

...