W tym miejscu napotkasz kilka problemów. Mechanizm unikania głodu w harmonogramie zobaczy twoje zadania jako zablokowane, ponieważ czekają na procesy. Trudno będzie odróżnić zaklejoną nitkę od tej, która czeka na zakończenie procesu. W rezultacie może planować nowe zadania, jeśli Twoje zadania są uruchamiane lub przez dłuższy czas (patrz poniżej). Hierarchia skoczków powinna uwzględniać całkowite obciążenie systemu, zarówno z aplikacji, jak i innych. Po prostu stara się zmaksymalizować wykonaną pracę, więc zwiększy ilość pracy do momentu, aż całkowita przepustowość systemu przestanie rosnąć, a następnie się wycofa. Nie sądzę, że będzie to miało wpływ na Twoją aplikację, ale prawdopodobnie problem unikania stavation.
można znaleźć więcej szczegółów, jak to wszystko działa w Parallel Programming with Microsoft®.NET, Colin Campbell, Ralph Johnson, Ade Miller, Stephen Toub (wcześniejszy projekt jest online).
„Basen wątek .NET automatycznie zarządza liczbę pracownika wątków w puli Dodaje i usuwa wątki według wbudowaną heurystyki Basen wątek .NET ma dwa główne mechanizmy wstrzykiwanie wątki. A. mechanizm głód unikania który dodaje pracownikowi wątki jeśli nie widzi postępy poczyniono przy kolejce przedmiotów i hillclimbing heurystyki, która stara się zmaksymalizować wydajność podczas korzystania jako kilku wątków, jak to możliwe.
celem uniknięcia głodu jest zapobieganie Ten rodzaj impasu może wystąpić, gdy pracownik odczyt czeka na zdarzenie synchronizacji , które może zostać spełnione tylko przez element pracy, który wciąż oczekuje na kolejkę globalną lub lokalną puli wątków. Jeśli liczba wątków roboczych byłaby stała , a wszystkie te wątki były zablokowane w podobny sposób, system nie byłby w stanie dokonać dalszego postępu. Dodanie nowego wątku roboczego rozwiązuje problem.
Celem heurystyki wspinaczki górskiej jest poprawa wykorzystania rdzeni, gdy wątki są blokowane przez I/O lub inne warunki oczekiwania , które powodują zatrzymanie procesora. Domyślnie zarządzana pula wątków ma jeden wątek roboczy dla każdego rdzenia. Jeśli jeden z tych wątków roboczych zostanie zablokowany , istnieje szansa, że rdzeń może być niedostatecznie wykorzystany, w zależności od ogólnego obciążenia komputera w zakresie .Logika wtrysku nici nie rozróżnia wątku, który jest zablokowany, oraz wątku , który wykonuje długotrwałą operację wymagającą dużej mocy obliczeniowej. Dlatego za każdym razem, gdy globalne lub lokalne koleje puli wątków zawierają oczekujące pozycje pracy, aktywne elementy pracy, które trwają długo (ponad pół sekundy), mogą wywołać tworzenie nowych wątków robota puli wątków .
Pula wątków .NET ma możliwość wstrzyknięcia wątków co jeden czas zakończenia pracy lub co 500 milisekund, w zależności od tego, która z nich jest krótsza niż . Puli wątków używa tej okazji, aby spróbować dodać wątki (lub zabranie ich), kierując się informacjami zwrotnymi z poprzednich zmian w liczbę wątków. Jeśli dodawanie wątków pomaga zwiększyć przepustowość, pula wątków dodaje więcej; w przeciwnym razie zmniejsza liczbę wątków roboczych . Technika ta nazywana jest heurystyką wspinaczki górskiej. Dlatego jednym z powodów, aby zadbać o pojedyncze zadania, jest uniknięcie "wykrywania głodu" pod numerem , ale innym powodem, aby je niedługo było, aby dać puli wątków więcej możliwości zwiększenia przepustowości o dostosowując liczbę wątków. Im krótszy jest czas wykonywania poszczególnych zadań, tym częściej pula wątków może mierzyć przepustowość, a dostosowuje odpowiednio liczbę wątków.
Aby to zrobić, zastanów się nad ekstremalnym przykładem. Załóżmy, że masz kompleksową symulację finansową z 500 procesorami wymagającymi intensywnego przetwarzania . Każda z nich zajmuje średnio dziesięć minut średnio . Jeśli utworzysz zadania najwyższego poziomu w globalnej kolejce dla każdej z tych operacji, po około pięciu minutach puli wątków wzrośnie do 500 wątków roboczych. Powodem jest to, że pula wątków widzi wszystkie zadania jako zablokowane i zaczyna dodawać nowe wątki z szybkością około dwóch wątków na sekundę.
Co jest nie tak w przypadku 500 wątków roboczych? Zasadniczo nic, jeśli masz do dyspozycji 500 rdzeni i ogromną ilość pamięci systemowej . W rzeczywistości jest to długoterminowa wizja obliczeń równoległych. Jeśli jednak nie masz zbyt wielu rdzeni na komputerze, jesteś w sytuacji, gdy wiele wątków rywalizuje o przesunięcia czasowe. Ta sytuacja znana jest jako nadmierna liczba subskrypcji procesora. Umożliwienie wielu procesorom wymagającym intensywnego przetwarzania do konkurowania o czas w jednym rdzeniu zwiększa obciążenie kontekstowe przełączaniem , co może poważnie zmniejszyć ogólną przepustowość systemu . Nawet jeśli nie zabraknie pamięci, wydajność w tej sytuacji może być o wiele, dużo gorsza niż w obliczeniach sekwencyjnych. (Każdy przełącznik kontekstowy zajmuje od 6000 do 8 000 cykli procesora). Koszt przełączania kontekstu nie jest jedynym źródłem kosztów ogólnych. Zarządzany wątek w .NET zużywa mniej więcej megabajt przestrzeni stosu , niezależnie od tego, czy jest ona używana do wykonywania aktualnie używanych funkcji. Proces tworzenia nowego wątku trwa około 200 000 cykli procesora, a do wycofania wątku potrzeba około 100 000 cykli. Są to kosztowne operacje.
Dopóki twoje zadania nie trwają minut, algorytm wspinania się w wątku ostatecznie zorientuje się, że ma zbyt wiele wątków i sam wycina.Jeśli jednak masz zadania, które zajmują wątek roboczy przez wiele sekund lub minut lub godzin, ten odrzuci heurystykę puli wątków iw tym momencie musisz rozważyć alternatywę.
Pierwsza opcja polega na rozłożeniu aplikacji na krótsze zadania , które kończą się wystarczająco szybko, aby pomyślnie pomyślnie utworzyć pulę wątków , sterując liczbą wątków w celu uzyskania optymalnej przepustowości. Drugą możliwością jest zaimplementowanie własnego obiektu harmonogramu zadań obiektu, który nie wykonuje wstrzyknięcia nici. Jeśli twoje zadania mają długi czas trwania, nie potrzebujesz wysoce zoptymalizowanego harmonogramu zadań, ponieważ koszt planowania będzie nieistotny w porównaniu z czasem wykonania zadania. Program deweloperski MSDN® ma przykład implementacji prostego harmonogramu zadań , który ogranicza maksymalny stopień współdziałania . Aby uzyskać więcej informacji, zobacz sekcję "Dalsze czytanie" pod koniec tego rozdziału na stronie .
W ostateczności można użyć metody SetMaxThreads do skonfigurowania klasy pula wątków z górnej granicy liczby wątków roboczych, zwykle równej liczby rdzeni (jest to nieruchomość Environment.ProcessorCount) . Ta górna granica dotyczy cały proces, w tym wszystkie AppDomains „
Oczywiście, prawdopodobnie powinienem podłączyć "TaskCompletionSource" do zdarzenia "Process.Exited", a następnie użyć metody 'TranscodeAsync', która zwraca' Task'. Wtedy nie będzie blokowania. Wtedy mogę mieć drobniejszą kontrolę nad zadaniami, pozostając w kontakcie z OC. –