2016-12-03 2 views
3

Я довольно новичок в C#, и мне нужна помощь в оптимизации моего кода.Оптимизация двойного цикла для скорости выполнения

struct Data 
{ 
    public static int numberOfPixels; 
    public static string[] filePaths; 
    public static string[] fileNames; 
    public static double[] z; 
    public static int numberOfFrames; 
    public static byte[][] imageBuffer; 
    public static int bufferSize = 1000; 
    public static double[] num; 
    public static double[] den; 
} 
public class Methods 
{ 
    public void RetrieveFileList() 
    { 
     Console.WriteLine("Please enter the folder path where all measurement files are stored: "); 
     Data.filePaths = Directory.GetFiles(Console.ReadLine(),"*.bin"); 
     Data.fileNames = new string[Data.filePaths.Length]; 
     Data.numberOfFrames = Data.filePaths.Length; 
     Data.z = new double[Data.filePaths.Length]; 
     int n = 0; 
     foreach(string file in Data.filePaths) 
     { 
      Data.fileNames[n] = Path.GetFileNameWithoutExtension(file); 
      n++; 
     } 
    } 
    public void CreatePositionArray() 
    { 
     Console.WriteLine("Please enter the stepsize used during the scan in nanometers: "); 
     double stepsize = Convert.ToDouble(Console.ReadLine()); 
     int n = 0; 
     foreach(string file in Data.fileNames) 
     { 
      Data.z[n] = Convert.ToInt32(file) * stepsize/1000; 
      n++; 
     } 
    } 
    public void InitializeBufferArray() 
    { 
     Data.imageBuffer = new byte[Data.numberOfFrames][]; 
    } 
    public byte[] ReadBinaryFile(int index) 
    { 
     return File.ReadAllBytes(Data.filePaths[index]); ; 
    } 
    public void FillImageBuffer() 
    { 
     for (int i = 0; i < Data.bufferSize; i++) 
     { 
      Data.imageBuffer[i] = ReadBinaryFile(i); 
     } 
     Data.numberOfPixels = Data.imageBuffer[0].Length; 
     Data.num = new double[Data.numberOfPixels]; 
     Data.den = new double[Data.numberOfPixels]; 
    } 
} 
class Program 
{ 
    static void Main(string[] args) 
    { 
     Method.RetrieveFileList(); 
     Method.CreatePositionArray(); 
     Method.InitializeBufferArray(); 
     Method.FillImageBuffer(); 
     for(int i = 0; i < Data.numberOfFrames; i++) 
     { 
      for (int j = 0; j < Data.numberOfPixels; j++) 
      { 
       double der = Math.Pow(Data.imageBuffer[i+1][j] - Data.imageBuffer[i][j], 2); 
       if (der < 1) der = 0; 
       Data.num[j] = Data.num[j] + Data.z[i] * der; 
       Data.den[j] = Data.den[j] + der; 
      } 
     } 
    } 
} 

В частности, две петли в моем главном методе. Прямо сейчас этот цикл обрабатывает около 1000 кадров с 1210000 пикселей каждый. Одна итерация внешнего цикла занимает около 80 мс для выполнения. Что было бы лучшим способом здесь? Создайте несколько потоков и разделите мой буфер на предопределенные джонки или используйте класс Parallel? Буду признателен за любую помощь.

Спасибо.

+0

Действительно ли это работает? 'Data.imageBuffer [i + 1]' звучит как 'IndexOutOfRangeException' для меня. –

ответ

1

Возможно, вам нужно выполнить обратный цикл, чтобы уменьшить ссылки на индекс массива. Кроме того, вместо Math.pow (дер, 2), лучше использовать дер * дер - это немного быстрее

 Method.RetrieveFileList(); 
    Method.CreatePositionArray(); 
    Method.InitializeBufferArray(); 
    Method.FillImageBuffer(); 
     for (int j = 0; j < Data.numberOfPixels; j++) { 
     double num = 0 
     double den = 0; 
     for(int i = 0; i < Data.numberOfFrames; i++) { 
      double der = Data.imageBuffer[i+1][j] - Data.imageBuffer[i][j]  
      if ((der *= der) < 1) der = 0; 
      num += Data.z[i] * der; 
      den += der; 
     } 
     Data.num[j] = num; 
     Data.den[j] = den; 
    } 

Честно говоря, я не думаю, что это будет drammatically увеличить производительность.

+0

Мне это нравится! Также 'der = 0;' можно заменить на 'continue;' и верхний цикл можно легко переключить на 'Parallel.For'. +1 –

+0

Спасибо, Иван. Parallel.For - настоящая сенсация. Также ... кто-то, кто не любит «contunue», может использовать «if (der * der> = 1) {num + = ...; den + =.} Вместо :) – cyanide

0

Я работал с «слишком много циклов» в течение некоторого времени, и у меня была такая же проблема. Я зациклился 91 миллион раз, и мне потребовалось около 4-5 минут. То, что я сделал, чтобы разбить это до 20-30 секунд, было профилированием. Вы должны попробовать профилировщик Visual Studio. Это действительно помогает вам понять, какая строка кода значительно снижает производительность вашей программы. Я заметил, что никто не упоминал GPGPU (общее программирование на GPU/или что-то в этом роде). Если вы хотите выполнить свой код в каждом фрейме, GPGPU может это сделать! Вы можете использовать вычисляющие шейдеры OpenCL, Cudafy или DirectX/OpenGL. Если вы не хотите идти на GPU-программирование, то использование VS Profiler - ваша лучшая практика.