29 maja 2010

Paralell nie dla AMD?

W ostatnim poście pisałem o zaletach programowania równoległego przy użyciu pętli Paralell.For w .NET 4.0. Zafascynowany tematem obliczeń równoległych przeprowadziłem kilka testów z użyciem procesorów rodziny Intel. Wyniki otrzymane z pomiarów potwierdziły przekonanie, że nowa pętla to naprawdę dobre, szybkie i skuteczne narzędzie. Oczywiście, im wyższej klasy procesor, tym szybkość i różnice pomiędzy standardową pętlą for, a Paralell.For rosły wraz z modelem procesora.

Kilka dni temu wraz z moim bliskim znajomym (którego imię i nazwisko zostanie dla Was tajemnicą ;) ) rozpoczęliśmy testy na czterordzeniowym procesorze AMD Athlon X4 620 3.07 GHz. Wyniki, które uzyskaliśmy, wprawiły nas w osłupienie. Pomijając szybkość obliczeń, które trwały naprawdę chwilę, udowodniliśmy, że Paralell na tym procesorze przegrywa… i to niestety dość znacznie. Zdecydowaliśmy się wykonać serię pomiarów - po 10 dla każdego współczynnika, a następnie uśrednić otrzymane wyniki. Poniżej prezentujemy wykres otrzymanych wyników na procesorze AMD Athlon X4.

Paralell w AMD
Testowano: AMD Athlon X4 620 2.60@3.07GHz, RAM:2.00GB, 32 bitowy Windows 7 Ultimate.

Powyższe dość zaskakujące wyniki wykazują, że zwykła pętla for jest dwukrotnie szybsza od pętli Paralell. Nasuwa się więc pytanie, czy firma z Redmond zoptymalizowała nowe rozwiązania tylko pod procesory Intel? Oczywiście, czytając doniesienia prasowe przed wejściem na rynek nowej wersji .NET czy też Windows 7, można było zauważyć dość zaawansowaną współpracę pomiędzy korporacjami. Zastanawiający jest fakt, czy opisany problem dotyczy tylko jednej, kilku serii procesorów, czy może wszystkich procesorów AMD? Dziś, niestety, nie potrafię odpowiedzieć na te pytania. Mam nadzieję, że wkrótce opublikuję odpowiedź.

Dla wszystkich osób zainteresowanych współpracą i tematem udostępniam w moim profilu e-mail kontaktowy.

Na koniec chciałbym podziękować wszystkim moim przyjaciołom, którzy poświęcili swój cenny czas na przeprowadzenie analizy i testów.

22 maja 2010

Obliczenia równoległe w .NET 4.0 - Parallel.For

W ostatnim czasie obliczenia równoległe stały się dość ważnym i popularnym pojęciem w programowaniu. Wielordzeniowe procesory z dnia na dzień stają się standardowym wyposażeniem każdego komputera. Coraz to większe obciążenia obliczeniowe procesorów powodują poszukiwanie nowych rozwiązań z zakresu tworzenia aplikacji wykorzystujących więcej niż jeden rdzeń procesora.

W dość prosty sposób chciałbym wprowadzić pojęcie TPL (Task Parallel Library), ilustrując działanie nowe pętli programowej Parallel.For dostępnej w .NET 4.0.

Na początku zapoznajmy się z budową pętli Parallel.For.
Ogólny schemat pętli wygląda następująco:

Parallel.For(a,b,delegate(int i)
{
  //ciało pętli
});

Warto zauważyć, że pętla Parallel.For to tak naprawdę statyczna metoda z trzema argumentami. Pierwsze dwa argumenty przekazują początek zakresu pętli 'a' oraz koniec 'b', natomiast trzeci z nich określa delegata.

Pętla Parallel.For znajduje się w przestrzeni nazw "System.Threading.Tasks;"

usign System.Threading.Tasks;

Przeanalizujmy przykład:
Zakładamy, że nasza dość prosta aplikacja ma wykonać serię dość skomplikowanych obliczeń matematycznych. Celem aplikacji będzie porównanie wydajności standardowej pętli for, z pętlą Parallel.For.

Pomijając etap tworzenia interfejsu użytkownika skupmy się na obliczeniach. Do wykonania mamy serię obliczeń wyrażoną metodą:

private void Oblicz(int i, int wsp)
{
  for (int j = 0; j < 10000+wsp; j++)
      {
        wynik+=Math.Sqrt(wsp*i+Math.Sqrt((j+1))*Math.Sqrt(i+1))*j+i;
      }
}


Pomijając sens powyższego wzoru załóżmy, że metoda Oblicz(int i, int wsp) przyjmuje dwa argumenty:
- wsp: współczynnik zmiany złożoności obliczeń (większy od 0),
- i: kolejne iteracje porównywanej pętli.

Dodajmy na formę naszej aplikacji dwa przyciski typu Button oraz jedno pole typu textBox.

Następnie dodajmy obsługę zdarzenia przycisków.
Na początku skupmy się na pierwszej standardowej pętli for (przycisk 1):

private void button1_Click(object sender, EventArgs e)
{
  try
      {
       int wsp = Int32.Parse(textBox1.Text);
       DateTime poczatek = DateTime.Now;
       for (int i = 0; i < 500 * wsp; i++)
           {
            Oblicz(i, wsp);
           }
       DateTime koniec = DateTime.Now;
       TimeSpan czas = koniec - poczatek;
       MessageBox.Show("Czas wykonania pętli for: " + czas.Seconds + " s : "+czas.Milliseconds + " ms");
      }
  catch
      {
       MessageBox.Show("Podano błędny zakres. Zakres > 0. Preferowana wartość 4");
      }
}


Jak widać zadaniem metody jest wywołanie kolejnej metody Oblicz(i, wsp) o określonej ilości iteracji. Zadanie zostało zrealizowane zwykłą programową pętlą for. Dodatkowo po wykonaniu obliczeń wyświetlimy komunikat o czasie, jaki potrzebował procesor na wykonanie obliczeń.

Następnie wykonamy takie same obliczenia wykorzystując pętlę Parallel.For, jednocześnie zwracając czas jaki potrzebował procesor na wykonanie obliczeń. Poniżej kod obsługi drugiego przycisku:

private void button2_Click(object sender, EventArgs e)
{
  try
     {
       int wsp = Int32.Parse(textBox1.Text);
       DateTime poczatek = DateTime.Now;
       Parallel.For(0,500*wsp, delegate(int i)
       {
         Oblicz(i, wsp);
       });
       DateTime koniec = DateTime.Now;
       TimeSpan czas = koniec - poczatek;
       MessageBox.Show("Czas wykonania pętli for: " + czas.Seconds + " s : " + czas.Milliseconds + " ms");;
     }
  catch
        {
          MessageBox.Show("Podano błędny zakres. Zakres > 0. Preferowana wartość 4");
        }
}


Pole typu textBox służy do wprowadzania wartości współczynnika 'wsp'. Zakładamy, że im większa wartość współczynnika, tym program wykona więcej obliczeń. Oczywiście wartość ta musi być większa od zera!
Preferuję testowanie programu na współczynniku z zakresu (0,9>.


Porównanie dwóch pętli względem czasu i przyjętego współczynnika (wsp).


Testowano: Intel Core 2 Duo T5800 2.00GHz, RAM:2.00 GB, 32 bitowy Windows 7 Professional.

Z wykresu możemy zauważyć ponad dwukrotny zysk używając pętli Parallel.For, który uzyskałem na dwurdzeniowym procesorze.

Mam nadzieję, że ten prosty przykład przestawił jak duży potencjał zawiera programowanie równoległe i TPL. Zachęcam do szerszego zapoznania się z tematem pętli Parallel.For

Pliki źródłowe opisanej aplikacji w środowisku Visual Studio C# 2010 Express, .NET 4.0.

Nie ponoszę odpowiedzialności za błędy i następstwa powstałe wskutek działania programu i kodu. Pobierasz i użytkujesz na własną odpowiedzialność.