Opcje scalania w PLINQ
Gdy zapytanie jest wykonywane jako równoległe, plINQ partycjonuje sekwencję źródłową, aby wiele wątków mogło działać na różnych częściach jednocześnie, zazwyczaj w osobnych wątkach. Jeśli wyniki mają być używane w jednym wątku, na przykład w pętli (For Each
w foreach
Visual Basic), wyniki z każdego wątku należy scalić z powrotem z jedną sekwencją. Rodzaj scalania wykonywanego przez PLINQ zależy od operatorów, które znajdują się w zapytaniu. Na przykład operatory, które nakładają nową kolejność na wyniki, muszą buforować wszystkie elementy ze wszystkich wątków. Z perspektywy wątku zużywania (który jest również użytkownikiem aplikacji) w pełni buforowane zapytanie może działać przez zauważalny okres czasu, zanim wygeneruje pierwszy wynik. Inne operatory domyślnie są częściowo buforowane; dają wyniki w partiach. Jeden operator ForAll nie jest domyślnie buforowany. Daje wszystkie elementy ze wszystkich wątków natychmiast.
Korzystając z WithMergeOptions metody , jak pokazano w poniższym przykładzie, można podać wskazówkę dla PLINQ, która wskazuje, jakiego rodzaju scalanie wykonać.
var scanLines = from n in nums.AsParallel()
.WithMergeOptions(ParallelMergeOptions.NotBuffered)
where n % 2 == 0
select ExpensiveFunc(n);
Dim scanlines = From n In nums.AsParallel().WithMergeOptions(ParallelMergeOptions.NotBuffered)
Where n Mod 2 = 0
Select ExpensiveFunc(n)
Pełny przykład można znaleźć w temacie How to: Specify Merge Options in PLINQ (Instrukcje: określanie opcji scalania w plINQ).
Jeśli określone zapytanie nie może obsługiwać żądanej opcji, opcja zostanie po prostu zignorowana. W większości przypadków nie trzeba określać opcji scalania dla zapytania PLINQ. Jednak w niektórych przypadkach można znaleźć przez testowanie i pomiar, że zapytanie wykonuje najlepiej w trybie nie domyślnym. Typowym zastosowaniem tej opcji jest wymuszenie przesyłania strumieniowego wyników operatora scalania fragmentów w celu zapewnienia bardziej dynamicznego interfejsu użytkownika.
ParallelMergeOptions
Wyliczenie ParallelMergeOptions zawiera następujące opcje, które określają, dla obsługiwanych kształtów zapytania, jak końcowe dane wyjściowe zapytania są zwracane, gdy wyniki są używane w jednym wątku:
Not Buffered
Opcja NotBuffered powoduje, że każdy przetworzony element jest zwracany z każdego wątku zaraz po jego wygenerowaniu. To zachowanie jest analogiczne do "przesyłania strumieniowego" danych wyjściowych. AsOrdered Jeśli operator znajduje się w zapytaniu,
NotBuffered
zachowuje kolejność elementów źródłowych. Mimo żeNotBuffered
zaczyna przynosić wyniki natychmiast po ich udostępnieniu, łączny czas na wygenerowanie wszystkich wyników może być nadal dłuższy niż użycie jednej z pozostałych opcji scalania.Auto Buffered
Opcja AutoBuffered powoduje, że zapytanie zbiera elementy do buforu, a następnie okresowo zwraca zawartość buforu jednocześnie do wątku zużywanego. Jest to analogiczne do uzyskiwania danych źródłowych w "fragmentach" zamiast używania zachowania "przesyłania strumieniowego" elementu
NotBuffered
.AutoBuffered
może potrwać dłużej niżNotBuffered
udostępnienie pierwszego elementu w wątku zużywających. Rozmiar buforu i dokładne zachowanie wydajności nie są konfigurowalne i mogą się różnić w zależności od różnych czynników związanych z zapytaniem.FullyBuffered
Opcja FullyBuffered powoduje buforowanie danych wyjściowych całego zapytania przed uzyskaniem któregokolwiek z elementów. Jeśli używasz tej opcji, może upłynąć dłużej, zanim pierwszy element będzie dostępny w wątku zużywania, ale pełne wyniki mogą być nadal generowane szybciej niż przy użyciu innych opcji.
Operatory zapytań, które obsługują opcje scalania
W poniższej tabeli wymieniono operatory, które obsługują wszystkie tryby opcji scalania, z zastrzeżeniem określonych ograniczeń.
Operator | Ograniczenia |
---|---|
AsEnumerable | Brak |
Cast | Brak |
Concat | Nieskonsekcyjne zapytania, które mają tylko źródło tablicy lub listy. |
DefaultIfEmpty | Brak |
OfType | Brak |
Reverse | Nieskonsekcyjne zapytania, które mają tylko źródło tablicy lub listy. |
Select | Brak |
SelectMany | None |
Skip | None |
Take | None |
Where | Brak |
Wszystkie inne operatory zapytań PLINQ mogą ignorować dostępne przez użytkownika opcje scalania. Niektóre operatory zapytań, na przykład Reverse i OrderBy, nie mogą zwracać żadnych elementów do momentu utworzenia i zmiany kolejności wszystkich elementów. W związku z tym, gdy ParallelMergeOptions jest używany w zapytaniu zawierającym również operator, taki jak Reverse, zachowanie scalania nie zostanie zastosowane w zapytaniu, dopóki ten operator nie wygenerował wyników.
Możliwość obsługi opcji scalania niektórych operatorów zależy od typu sekwencji źródłowej i tego, czy AsOrdered operator został użyty wcześniej w zapytaniu. ForAll jest zawsze NotBuffered ; daje swoje elementy natychmiast. OrderBy jest zawsze FullyBuffered; musi posortować całą listę, zanim zostanie ona wyświetlona.