Udostępnij przez


Typowe wzorce dla źle działających aplikacji wielowątkowych

Narzędzie do wizualizacji współbieżności ułatwia programistom wizualizowanie zachowania aplikacji wielowątkowej. To narzędzie zawiera galerię typowych wzorców dla aplikacji wielowątkowych, które działają nieprawidłowo. Galeria zawiera typowe i rozpoznawalne wzorce wizualne, które są uwidocznione za pomocą narzędzia, wraz z wyjaśnieniem zachowania reprezentowanego przez każdy wzorzec, prawdopodobnym wynikiem tego zachowania i najczęstszym podejściem do jego rozwiązania.

Spór o blokadę i sekwencyjne wykonywanie

Blokowanie rywalizacji w wyniku serializacji wykonywania

Czasami równoległa aplikacja uparcie kontynuuje wykonywanie w trybie szeregowym, mimo że ma kilka wątków, a komputer ma wystarczającą liczbę rdzeni logicznych. Pierwszy objaw jest słabszą wydajnością wielowątkową, być może nawet nieco wolniejszą niż implementacja szeregowa. W widoku wątków nie widać wielu wątków uruchomionych równolegle; Zamiast tego widać, że tylko jeden wątek jest wykonywany w dowolnym momencie. W tym momencie, jeśli klikniesz segment synchronizacji w wątku, zobaczysz stos wywołań dla zablokowanego wątku (blokujący stos wywołań) i wątek, który usunął warunek blokowania (odblokowywanie stosu wywołań). Ponadto, jeśli stos wywołań odblokowywania występuje w analizowanym procesie, wyświetlony zostanie łącznik typu Thread-Ready. Od tego momentu możesz przejść do swojego kodu poprzez stosy wywołań blokujących i odblokowujących, aby dokładniej zbadać przyczynę serializacji.

Jak pokazano na poniższej ilustracji, wizualizator współbieżności może również uwidocznić ten objaw w widoku wykorzystania procesora CPU, gdzie pomimo obecności wielu wątków aplikacja zużywa tylko jeden rdzeń logiczny.

Aby uzyskać więcej informacji, zobacz sekcję "Zacznij od sekcji dotyczącej problemu" w artykule Thread Performance - Profilowanie zawartości zasobów i współbieżności w programie Visual Studio.

Blokowanie rywalizacji

Nierównomierna dystrybucja obciążeń

Zrzut ekranu przedstawiający wykres obciążenia roboczego dla wątków równoległych w Concurrency Visualizer. Wątki kończą się w różnym czasie, pokazując wzorzec schodkowy.

Gdy nieregularny rozkład pracy występuje w kilku równoległych wątkach w aplikacji, typowy wzorzec schodów pojawia się, gdy każdy wątek kończy swoją pracę, jak pokazano na poprzedniej ilustracji. Wizualizator współbieżności najczęściej pokazuje bardzo bliskie godziny rozpoczęcia dla każdego współbieżnego wątku. Jednak te wątki zwykle kończą się nieregularnie zamiast kończyć się jednocześnie. Ten wzorzec wskazuje nieregularny rozkład pracy między grupą wątków równoległych, co może prowadzić do zmniejszenia wydajności. Najlepszym podejściem do takiego problemu jest ponowne obliczanie algorytmu, za pomocą którego praca została podzielona między wątki równoległe.

Jak pokazano na poniższej ilustracji, Visualizator Równoczesności może również pokazać ten objaw w widoku wykorzystania procesora jako stopniowe zmniejszenie wykorzystania procesora.

Zrzut ekranu przedstawiający Widok Wykorzystania CPU w Wizualizatorze Współbieżności pokazujący wzorzec schodów na końcu grafu Wykorzystanie CPU.

Nadsubskrypcji

Zrzut ekranu przedstawiający wykres obciążenia dla wszystkich aktywnych wątków w wizualizatorze współbieżności. Legenda pokazuje ilość czasu poświęcanego na wykonywanie i wywłaszczanie.

W przypadku nadsubskrybowania liczba aktywnych wątków w procesie jest większa niż liczba dostępnych rdzeni logicznych w systemie. Na poprzedniej ilustracji przedstawiono wyniki nadsubskrypcji z wyraźnymi przerwaniami we wszystkich aktywnych wątkach. Ponadto legenda pokazuje duży procent czasu poświęcanego na wywłaszczanie (84 procent w tym przykładzie). Może to wskazywać, że proces prosi system o wykonanie większej liczby współbieżnych wątków niż liczba rdzeni logicznych. Jednak może to również wskazywać, że inne procesy w systemie korzystają z zasobów, które zostały przyjęte jako dostępne dla tego procesu.

Podczas oceny tego problemu należy wziąć pod uwagę następujące kwestie:

  • Ogólny system może być nadmiernie obciążony. Należy wziąć pod uwagę, że inne procesy w systemie mogą wywłaszczać wątki. Gdy zatrzymasz się nad segmentem wywłaszczenia w widoku wątków, podpowiedź zidentyfikuje wątek oraz proces, który wywłaszczył wątek. Ten proces nie musi być tym, który był wykonywany przez cały czas, kiedy Twój proces został wywłaszczony, ale udostępnia wskazówkę dotyczącą tego, co spowodowało powstanie nacisku wywłaszczającego na Twój proces.

  • Oceń, w jaki sposób proces określa odpowiednią liczbę wątków do wykonania w tej fazie pracy. Jeśli proces oblicza bezpośrednio liczbę aktywnych wątków równoległych, rozważ zmodyfikowanie tego algorytmu, aby lepiej uwzględnić liczbę dostępnych rdzeni logicznych w systemie. Jeśli używasz Concurrency Runtime, Biblioteki Zadań Równoległych lub PLINQ, te biblioteki zajmują się obliczaniem liczby wątków.

Nieefektywne wejście/wyjście

Nieefektywne we/wy

Nadmierne lub niewłaściwe użycie operacji I/O jest częstą przyczyną nieefektywności w aplikacjach. Rozważmy poprzednią ilustrację. Profil widocznej osi czasu pokazuje, że 44 procent widocznego czasu wątku jest używane przez we/wy. Oś czasu przedstawia duże ilości operacji wejścia/wyjścia, co wskazuje, że profilowana aplikacja jest często blokowana przez wejście/wyjście. Aby zobaczyć szczegółowe informacje na temat rodzajów operacji I/O i miejsc, w których program jest zablokowany, zbliż problematyczne regiony, przejrzyj profil osi czasu, który jest widoczny, a następnie kliknij określony blok I/O, aby zobaczyć bieżące stosy wywołań.

Blokowanie konwojów

Blokowanie konwojów

Konwoje zablokowania występują, gdy aplikacja uzyskuje blokady w kolejności przybycia, a tempo przybycia do blokady jest wyższe niż tempo ich uzyskiwania. Połączenie tych dwóch warunków powoduje, że żądania dotyczące blokady zaczynają się piętrzyć. Jednym ze sposobów zwalczania tego problemu jest użycie "niesprawiedliwych" blokad lub blokad, które dają dostęp do pierwszego wątku, aby znaleźć je w odblokowanych stanach. Na poprzedniej ilustracji przedstawiono to zachowanie konwoju. Aby rozwiązać ten problem, spróbuj zmniejszyć rywalizację o obiekty synchronizacji i spróbować użyć nieuczciwych blokad.

Widok wątków