Laboratorium 10: Programowanie równoległe i asynchroniczne #
Kod początkowy #
Student
- FlightScanner.API/
- FlightScanner.Client/
- FlightScanner.Common/
- FractalsGenerator/
- FractalsGenerator.csproj
- Generators/
- MandelbrotSet/
- Implementations/
- MandelbrotSetGenerator.cs
- Program.cs
- student.sln
Generowanie fraktali #
Czym jest programowanie równoległe?
Programowanie równoległe to paradygmat programowania, wykorzystujący architekturę nowoczesnych, wielordzeniowych procesorów (CPU) w celu wykonywania wielu obliczeń równocześnie.
Zamiast przetwarzać dane sekwencyjnie w jednym wątku, rozdzielamy pracę na wiele wątków, które wykonują swoją pracę w tym samym momencie.
Opis zadania #
Celem zadania jest implementacja oraz porównanie czasu wykonania różnych metod zrównoleglających obliczenia wykonywane podczas generowania Zbioru Mandelbrota.
Kod początkowy zawiera abstrakcyjną klasę MandelbrotSetGenerator, która zarządza całym procesem generowania fraktala i zapisywania go do pliku .png
Klasa SingleThreadGenerator stanowi konkretną jednowątkową implementację generatora. Używa ona prostej, zagnieżdżonej pętli for do iteracji po wszystkich pikselach generowanego obrazka. Posłuży jako linia bazowa do pomiaru wydajności.
Należy zaimplementować następujące metody zrównoleglania obliczeń:
MultiThreadGenerator: Metoda wielowątkowa, która ręcznie tworzy i zarządza obiektamiThread.TasksGenerator: Metoda, która używa klasyTaskz biblioteki TPL (ang. Task Parallel Library) do zarządzania pracą równoległą w puli wątków (ThreadPool).ParallelGenerator: Metoda, która używa wysokopoziomowej klasyParallelz biblioteki TPL.
Program.cs zawiera logikę mierzenia czasu i uruchamiania każdego generatora po kolei.
Poprawnie wygenerowany fraktal powinien wyglądać następująco:

Uwagi implementacyjne
- Liczba wątków:
- W implementacjach
MultiThreadGeneratoriTasksGeneratornależy stworzyćNjednostek pracy (wątków/zadań), gdzieNjest równe liczbie rdzeni procesora. Jest to optymalna liczba dla zadań w 100% obciążających CPU.- Podział pracy:
- W przypadku generowania fraktala, najprostszą strategią jest podział obrazu na
Nrównych, poziomych pasów.- Oblicz, ile wierszy przypada na jeden wątek, a następnie w pętli przekaż każdemu wątkowi/zadaniu odpowiedni zakres do przetworzenia.
Materiały pomocnicze:
Przykładowe rozwiązanie #
Rozwiązanie
- FractalsGenerator.csproj
- Generators/
- MandelbrotSet/
- Program.cs
Agregator ofert #
Czym jest programowanie asynchroniczne?
Programowanie asynchroniczne służy do nieblokowania wątku wykonawczego podczas oczekiwania na operacje, które są poza naszą kontrolą.
Używamy go między innymi do takich zadań jak oczekiwanie na odpowiedź z sieci (API), wysyłanie zapytań do bazy danych, czy odczytywanie zawartości dużego pliku z dysku.
W tym przypadku, celem nie jest szybsze liczenie, a lepsze zarządzanie czasem oczekiwania i responsywnością aplikacji.
Opis zadania #
Celem zadania jest zbudowanie asynchronicznego klienta konsolowego (w projekcie FlightScanner.Client), który będzie agregował oferty lotnicze z wielu serwisów jednocześnie. Klient będzie komunikował się z lokalnie uruchomionym REST-owym API (projekt FlightScanner.API).
API, działające pod adresem http://localhost:5222 (adres można znaleźć w pliku launchSettings.json), jest w pełni zaimplementowane i nie wymaga modyfikacji. Należy je uruchomić przed uruchomieniem aplikacji konsolowej.
Na Linuxie uruchom projekt
FlightScanner.APIprzez dostarczony skryptrun.sh. Pobierze on brakujące środowisko uruchomienioweASP.NETi uruchomi projekt.
Aplikacja kliencka powinna:
- Jednokrotnie odpytać “centralny” endpoint API (
/api/providers), aby pobrać listę dostępnych linii lotniczych. - Dla każdej linii lotniczej z pobranej listy, aplikacja musi równocześnie (współbieżnie) wysłać zapytanie do jej dedykowanego endpointu (np.
/api/flights/reliable-air), aby pobrać konkretne oferty lotów. - Wszystkie pobrane oferty z różnych linii muszą zostać zebrane, odfiltrowane z błędów i zagregowane w jedną, “płaską” listę.
- Na koniec, aplikacja ma wyświetlić 10 najtańszych znalezionych ofert.
Modele Danych #
API operuje na następujących obiektach DTO (ang. Data Transfer Objects). Znajdują się one we współdzielonej bibliotece klas FlightScanner.Common.
// Received from /api/providers
public record PartnerAirlineDto(
string Id,
string Name,
string Endpoint
);
// Received from airline providers
public record ProviderResponseDto(
string ProviderName,
List<FlightOfferDto> Flights
);
// Part of ProviderResponseDto
public record FlightOfferDto(
string FlightId,
string Origin,
string Destination,
decimal Price
);Uwagi implementacyjne
- Współbieżność:
- Odpytywanie wszystkich linii lotniczych musi odbywać się w tym samym czasie, a nie sekwencyjnie.
- Globalny timeout:
- Cała operacja zbierania ofert musi mieć globalny limit czasu (np. 3 sekundy), narzucony przez
CancellationTokenSource.- Jeśli którykolwiek dostawca nie odpowie w tym czasie, jego oferta jest pomijana.
- Raportowanie postępu:
- Aplikacja musi raportować postęp w czasie rzeczywistym, używając interfejsu
IProgress<T>.- Odporność na Błędy:
- Jeśli endpoint jednego dostawcy zwróci błąd HTTP (np.
500,404) lub przekroczy limit czasu, aplikacja nie może się zatrzymać.- Powinna zignorować tego dostawcę i kontynuować pracę z pozostałymi.
Materiały pomocnicze:
Przykładowe rozwiązanie #
Rozwiązanie