Nuta
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować się zalogować lub zmienić katalog.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Biblioteka wzorców równoległych (PPL) udostępnia model programowania imperatywnego, który promuje skalowalność i łatwość użycia do tworzenia współbieżnych aplikacji. PPL opiera się na składnikach planowania i zarządzania zasobami środowiska uruchomieniowego współbieżności. Podnosi ona poziom abstrakcji między kodem aplikacji a bazowym mechanizmem wątkowania, zapewniając ogólne, bezpieczne dla typów algorytmy i kontenery, które działają równolegle na danych. PPL umożliwia również tworzenie aplikacji skalowanych przez udostępnienie alternatyw dla stanu współużytkowanego.
PPL oferuje następujące funkcje:
Równoległość zadań: mechanizm, który działa w górnej części puli wątków systemu Windows w celu równoległego wykonywania kilku elementów roboczych (zadań)
Algorytmy równoległe: ogólne algorytmy, które działają na podstawie środowiska uruchomieniowego współbieżności, aby działać równolegle na kolekcjach danych
Kontenery równoległe i obiekty: ogólne typy kontenerów, które zapewniają bezpieczny współbieżny dostęp do ich elementów
Przykład
PPL udostępnia model programowania podobny do standardowej biblioteki języka C++. W poniższym przykładzie pokazano wiele funkcji PPL. Oblicza kilka liczb Fibonacciego szeregowo i równolegle. Oba obliczenia działają na obiekcie std::array . Przykład wyświetla również w konsoli czas wymagany do wykonania obu obliczeń.
Wersja szeregowa używa algorytmu std::for_each biblioteki standardowej języka C++ do przechodzenia przez tablicę i przechowywania wyników w obiekcie std::vector. Wersja równoległa wykonuje to samo zadanie, ale używa współbieżności PPL ::p arallel_for_each algorytmu i przechowuje wyniki w obiekcie concurrency::concurrent_vector . Klasa concurrent_vector umożliwia iteracji każdej pętli równoczesne dodawanie elementów bez konieczności synchronizowania dostępu zapisu do kontenera.
Ponieważ parallel_for_each działa współbieżnie, równoległa wersja tego przykładu musi posortować concurrent_vector obiekt, aby wygenerować te same wyniki co wersja szeregowa.
Zwróć uwagę, że w przykładzie użyto metody naiwnej do obliczenia liczb Fibonacciego; Jednak ta metoda ilustruje, w jaki sposób środowisko uruchomieniowe współbieżności może poprawić wydajność długich obliczeń.
// parallel-fibonacci.cpp
// compile with: /EHsc
#include <windows.h>
#include <ppl.h>
#include <concurrent_vector.h>
#include <array>
#include <vector>
#include <tuple>
#include <algorithm>
#include <iostream>
using namespace concurrency;
using namespace std;
// Calls the provided work function and returns the number of milliseconds
// that it takes to call that function.
template <class Function>
__int64 time_call(Function&& f)
{
__int64 begin = GetTickCount();
f();
return GetTickCount() - begin;
}
// Computes the nth Fibonacci number.
int fibonacci(int n)
{
if(n < 2)
return n;
return fibonacci(n-1) + fibonacci(n-2);
}
int wmain()
{
__int64 elapsed;
// An array of Fibonacci numbers to compute.
array<int, 4> a = { 24, 26, 41, 42 };
// The results of the serial computation.
vector<tuple<int,int>> results1;
// The results of the parallel computation.
concurrent_vector<tuple<int,int>> results2;
// Use the for_each algorithm to compute the results serially.
elapsed = time_call([&]
{
for_each (begin(a), end(a), [&](int n) {
results1.push_back(make_tuple(n, fibonacci(n)));
});
});
wcout << L"serial time: " << elapsed << L" ms" << endl;
// Use the parallel_for_each algorithm to perform the same task.
elapsed = time_call([&]
{
parallel_for_each (begin(a), end(a), [&](int n) {
results2.push_back(make_tuple(n, fibonacci(n)));
});
// Because parallel_for_each acts concurrently, the results do not
// have a pre-determined order. Sort the concurrent_vector object
// so that the results match the serial version.
sort(begin(results2), end(results2));
});
wcout << L"parallel time: " << elapsed << L" ms" << endl << endl;
// Print the results.
for_each (begin(results2), end(results2), [](tuple<int,int>& pair) {
wcout << L"fib(" << get<0>(pair) << L"): " << get<1>(pair) << endl;
});
}
Następujące przykładowe dane wyjściowe są przeznaczone dla komputera z czterema procesorami.
serial time: 9250 ms
parallel time: 5726 ms
fib(24): 46368
fib(26): 121393
fib(41): 165580141
fib(42): 267914296
Każda iteracja pętli wymaga innego czasu na zakończenie. Wydajność parallel_for_each elementu jest powiązana przez operację, która kończy się ostatnio. W związku z tym nie należy oczekiwać poprawy wydajności liniowej między wersjami seryjnymi i równoległymi w tym przykładzie.
Tematy pokrewne
| Nazwa | opis |
|---|---|
| Równoległość zadań | Opisuje rolę zadań i grup zadań w PPL. |
| Algorytmy równoległe | Opisuje sposób używania algorytmów równoległych, takich jak parallel_for i parallel_for_each. |
| Równoległe kontenery oraz obiekty | Opisuje różne równoległe kontenery i obiekty udostępniane przez PPL. |
| Anulowanie w PPL | Wyjaśnia, jak anulować pracę wykonywaną przez algorytm równoległy. |
| Środowisko uruchomieniowe współbieżności | Opisuje środowisko uruchomieniowe współbieżności, które upraszcza programowanie równoległe i zawiera linki do powiązanych tematów. |