Po naszej sesji pojawiły się dwa pytania, na które udzieliliśmy odpowiedzi, której nie byliśmy do końca pewni. Oczywiście zaznaczyliśmy, że najlepiej jest to przetestować i zobaczyć jak zachowa się telefon. Wyniki potwierdziły nasze odpowiedzi.
Pytanie 1
Pierwsze pytanie dotyczyło tego, czy nie wystarczy jedynie zamienić kolejności pętli, aby uzyskać podobne przyspieszenie działania programu, bez wyciągania operacji wyliczenia indeksu. Wtedy nasz kod zmieni się z poniższego:
public void Convert1(WriteableBitmap bitmap)
{
int[] grayScale = new int[bitmap.PixelHeight * bitmap.PixelWidth];
for (int i = 0; i < bitmap.PixelWidth; i++)
{
for (int j = 0; j < bitmap.PixelHeight; j++)
{
Color currentColor = this.ConvertToColor(
bitmap.Pixels[i + (bitmap.PixelHeight * j)]);
Color grayColor = this.ToGrayScale(currentColor);
grayScale[i + (bitmap.PixelHeight * j)] = this.ToIntFromColor(grayColor);
}
}
}
Na następujący:
public void Convert2(WriteableBitmap bitmap)
{
int[] grayScale = new int[bitmap.PixelHeight * bitmap.PixelWidth];
for (int j = 0; j < bitmap.PixelHeight; j++)
{
for (int i = 0; i < bitmap.PixelWidth; i++)
{
Color currentColor = this.ConvertToColor(
bitmap.Pixels[i + (bitmap.PixelHeight * j)]);
Color grayColor = this.ToGrayScale(currentColor);
grayScale[i + (bitmap.PixelHeight * j)] = this.ToIntFromColor(grayColor);
}
}
}
Dla przypomnienia podam jeszcze zaproponowaną przez nas wersję pierwszego kroku optymalizacji:
public void Convert3(WriteableBitmap bitmap)
{
int[] grayScale = new int[bitmap.PixelHeight * bitmap.PixelWidth];
for (int j = 0; j < bitmap.PixelHeight; j++)
{
int heightIndex = bitmap.PixelHeight * j;
for (int i = 0; i < bitmap.PixelWidth; i++)
{
int pixelIndex = i + heightIndex;
Color currentColor = this.ConvertToColor(bitmap.Pixels[pixelIndex]);
Color grayColor = this.ToGrayScale(currentColor);
grayScale[pixelIndex] = this.ToIntFromColor(grayColor);
}
}
}
Jak pokazują testy na urządzeniach – na każdym z nich zostało wykonane 1000 pomiarów – czas uległ skróceniu, ale nieznacznie. Poniżej zamieszczam tabelę z wynikami:
| Metoda | Nokia Lumia 800 | HTC Titan | HTC 7 Pro |
| Convert1 | 236,57 ms | 263,42 ms | 393,08 ms |
| Convert2 | 223,17 ms | 234,88 ms | 350,30 ms |
| Convert3 | 179,32 ms | 170,63 ms | 253,50 ms |
Na podstawie otrzymanych wyników możemy zaobserwować, że pierwsza modyfikacja skróciła czas wykonywania metody średnio o 9%. Natomiast jednokrotne obliczenie indeksu wraz z redukcją ilości wykonywanych operacji mnożenia oraz zamiana kolejności wykonywania pętli skraca czas wykonywania metody średnio o 32%.
Pytanie 2
Drugie pytanie dotyczyło finalnej implementacji:
public void Convert4(WriteableBitmap bitmap)
{
int[] pixels = bitmap.Pixels;
int length = pixels.Length;
int[] grayScale = new int[length];
for (int i = 0; i < length; i++)
{
int currentPixel = pixels[i];
int a = (byte)(currentPixel >> 24);
int r = (byte)(currentPixel >> 16);
int g = (byte)(currentPixel >> 8);
int b = (byte)currentPixel;
int gray = (6966 * r + 23436 * g + 2366 * b) >> 15;
int grayColor = (a << 24) | (gray << 16) | (gray << 8) | gray;
grayScale[i] = grayColor;
}
}
Pojawił się pomysł, aby wyciągnąć deklarację zmiennych [mark]int[/mark] przez pętlę i zobaczyć co się stanie:
public void Convert5(WriteableBitmap bitmap)
{
int[] pixels = bitmap.Pixels;
int length = pixels.Length;
int[] grayScale = new int[length];
int currentPixel, a, r, g, b, gray, grayColor;
for (int i = 0; i < length; i++)
{
currentPixel = pixels[i];
a = (byte)(currentPixel >> 24);
r = (byte)(currentPixel >> 16);
g = (byte)(currentPixel >> 8);
b = (byte)currentPixel;
gray = (6966 * r + 23436 * g + 2366 * b) >> 15;
grayColor = (a << 24) | (gray << 16) | (gray << 8) | gray;
grayScale[i] = grayColor;
}
}
W tym przypadku, nie udało się zaobserwować żadnej zmiany. Zarówno czas wykonania funkcji, jak również zużycie pamięci pozostało to samo.


Zostaw komentarz