Zarządzana pula wątków

Klasa System.Threading.ThreadPool udostępnia aplikacji pulę wątków roboczych zarządzanych przez system, co pozwala skoncentrować się na zadaniach aplikacji, a nie na zarządzaniu wątkami. Jeśli masz krótkie zadania wymagające przetwarzania w tle, zarządzana pula wątków jest łatwym sposobem korzystania z wielu wątków. Korzystanie z puli wątków jest znacznie łatwiejsze w programie Framework 4 lub nowszym, ponieważ można tworzyć TaskTask<TResult> obiekty, które wykonują zadania asynchroniczne w wątkach puli wątków.

Platforma .NET używa wątków puli wątków do wielu celów, w tym operacji biblioteki równoległej zadań (TPL ), asynchronicznego uzupełniania we/wy, wywołań zwrotnych czasomierza , zarejestrowanych operacji oczekiwania, asynchronicznych wywołań metod przy użyciu delegatów i System.Net połączeń gniazd.

Cechy puli wątków

Wątki puli wątków to wątki w tle . Każdy wątek używa domyślnego rozmiaru stosu, jest uruchamiany z domyślnym priorytetem i znajduje się w mieszkaniu wielowątkowym. Gdy wątek w puli wątków zakończy zadanie, zostanie on zwrócony do kolejki oczekujących wątków. Od tego momentu można go ponownie użyć. Ponowne użycie umożliwia aplikacjom uniknięcie kosztów tworzenia nowego wątku dla każdego zadania.

Istnieje tylko jedna pula wątków na proces.

Wyjątki w wątkach puli wątków

Nieobsługiwane wyjątki w wątkach puli wątków kończą proces. Istnieją trzy wyjątki od tej reguły:

Aby uzyskać więcej informacji, zobacz Wyjątki w zarządzanych wątkach.

Maksymalna liczba wątków puli wątków

Liczba operacji, które można kolejkować do puli wątków, jest ograniczona tylko przez dostępną pamięć. Jednak pula wątków ogranicza liczbę wątków, które mogą być aktywne w procesie jednocześnie. Jeśli wszystkie wątki puli wątków są zajęte, dodatkowe elementy robocze są kolejkowane do momentu udostępnienia wątków do ich wykonania. Domyślny rozmiar puli wątków dla procesu zależy od kilku czynników, takich jak rozmiar wirtualnej przestrzeni adresowej. Proces może wywołać metodę ThreadPool.GetMaxThreads w celu określenia liczby wątków.

Maksymalną liczbę wątków można kontrolować przy użyciu ThreadPool.GetMaxThreads metod i ThreadPool.SetMaxThreads .

Uwaga

Kod hostujący środowisko uruchomieniowe języka wspólnego może ustawić rozmiar przy użyciu ICorThreadpool::CorSetMaxThreads metody .

Minimum puli wątków

Pula wątków udostępnia nowe wątki robocze lub wątki uzupełniania we/wy na żądanie, dopóki nie osiągnie określonego minimum dla każdej kategorii. Możesz użyć ThreadPool.GetMinThreads metody , aby uzyskać te minimalne wartości.

Uwaga

Gdy zapotrzebowanie jest niskie, rzeczywista liczba wątków wątek puli wątków może spaść poniżej minimalnych wartości.

Po osiągnięciu minimum pula wątków może utworzyć dodatkowe wątki lub poczekać na ukończenie niektórych zadań. Pula wątków tworzy i niszczy wątki robocze w celu optymalizacji przepływności, która jest zdefiniowana jako liczba zadań, które są wykonywane w poszczególnych jednostkach czasu. Zbyt mało wątków może nie zapewnić optymalnego wykorzystania dostępnych zasobów, podczas gdy zbyt wiele wątków może zwiększyć rywalizację o zasoby.

Uwaga

Możesz użyć ThreadPool.SetMinThreads metody , aby zwiększyć minimalną liczbę bezczynnych wątków. Jednak niepotrzebne zwiększanie tych wartości może powodować problemy z wydajnością. Jeśli zbyt wiele zadań rozpoczyna się w tym samym czasie, wszystkie z nich mogą wydawać się powolne. W większości przypadków pula wątków będzie działać lepiej za pomocą własnego algorytmu przydzielania wątków.

Korzystanie z puli wątków

Najprostszym sposobem korzystania z puli wątków jest użycie biblioteki równoległej zadań (TPL). Domyślnie typy TPL, takie jak Task wątki puli wątków i Task<TResult> używają ich do uruchamiania zadań.

Pulę wątków można również użyć przez wywołanie ThreadPool.QueueUserWorkItem kodu zarządzanego (lub ICorThreadpool::CorQueueUserWorkItem z niezarządzanego kodu) i przekazanie delegata System.Threading.WaitCallback reprezentującego metodę wykonującą zadanie.

Innym sposobem użycia puli wątków jest kolejkowanie elementów roboczych, które są powiązane z operacją oczekiwania przy użyciu ThreadPool.RegisterWaitForSingleObject metody i przekazanie elementu System.Threading.WaitHandle , gdy zostanie zasygnalizowane lub gdy upłynął limit czasu, wywołuje metodę reprezentowaną przez delegata System.Threading.WaitOrTimerCallback . Wątki puli wątków są używane do wywoływania metod wywołania zwrotnego.

Aby zapoznać się z przykładami, sprawdź przywołyne strony interfejsu API.

Pomijanie kontroli zabezpieczeń

Pula wątków ThreadPool.UnsafeQueueUserWorkItem udostępnia również metody i ThreadPool.UnsafeRegisterWaitForSingleObject . Użyj tych metod tylko wtedy, gdy masz pewność, że stos obiektu wywołującego nie ma znaczenia dla wszelkich kontroli zabezpieczeń wykonywanych podczas wykonywania zadania w kolejce. ThreadPool.QueueUserWorkItem i ThreadPool.RegisterWaitForSingleObject przechwyć stos obiektu wywołującego, który jest scalony ze stosem wątku puli wątków, gdy wątek zaczyna wykonywać zadanie. Jeśli wymagane jest sprawdzenie zabezpieczeń, należy sprawdzić cały stos. Mimo że kontrola zapewnia bezpieczeństwo, ma również koszt wydajności.

Kiedy nie należy używać wątków puli wątków

Istnieje kilka scenariuszy, w których należy utworzyć własne wątki i zarządzać nimi zamiast używać wątków puli wątków:

  • Wymagany jest wątek pierwszego planu.
  • Aby wątek miał określony priorytet, musisz mieć określony priorytet.
  • Masz zadania, które powodują zablokowanie wątku przez długi czas. Pula wątków ma maksymalną liczbę wątków, więc duża liczba zablokowanych wątków puli wątków może uniemożliwić uruchamianie zadań.
  • Należy umieścić wątki w jednym wątkowym mieszkaniu. Wszystkie ThreadPool wątki znajdują się w wielowątkowym mieszkaniu.
  • Musisz mieć stabilną tożsamość skojarzona z wątkiem lub dedykować wątek do zadania.

Zobacz też