Wielowątkowość w języku C # z zadaniami

click fraud protection

The programowanie komputerowe termin „wątek” jest skrótem od wątku wykonania, w którym procesor podąża określoną ścieżką przez kod. Koncepcja śledzenia więcej niż jednego wątku naraz wprowadza temat wielozadaniowości i wielowątkowości.

Aplikacja zawiera jeden lub więcej procesów. Pomyśl o procesie jak o programie działającym na twoim komputerze. Teraz każdy proces ma jeden lub więcej wątków. Aplikacja do gry może mieć wątek do ładowania zasobów z dysku, inny do sztucznej inteligencji, a inny do uruchamiania gry jako serwer.

W .NET / Windows system operacyjny przydziela czas procesora wątkowi. Każdy wątek śledzi procedury obsługi wyjątków i priorytet, z jakim jest uruchamiany, i ma miejsce do zapisania kontekstu wątku, dopóki nie zostanie uruchomiony. Kontekst wątku to informacja, którą wątek musi wznowić.

Wielozadaniowość z wątkami

Wątki zajmują trochę pamięci, a ich tworzenie zajmuje trochę czasu, więc zwykle nie chcesz używać wielu. Pamiętaj, że rywalizują o czas procesora. Jeśli komputer ma wiele procesorów, system Windows lub .NET mogą uruchamiać każdy wątek na innym procesorze, ale jeśli kilka wątków działa na tym samym CPU, wtedy tylko jeden może być aktywny na raz i przełączanie wątków zajmuje czas.

instagram viewer

Procesor uruchamia wątek na kilka milionów instrukcji, a następnie przełącza się na inny wątek. Wszystkie rejestry procesora, bieżący punkt wykonania programu i stos muszą zostać zapisane gdzieś dla pierwszego wątku, a następnie przywrócone gdzieś indziej dla następnego wątku.

Tworzenie wątku

W systemie nazw. Gwintowanie, znajdziesz typ wątku. Wątek konstruktora (ThreadStart) tworzy instancję wątku. Jednak w ostatnim czasie DO# kodu, bardziej prawdopodobne jest przekazanie wyrażenia lambda, które wywołuje metodę z dowolnymi parametrami.

Jeśli nie jesteś pewien wyrażenia lambda, może warto sprawdzić LINQ.

Oto przykład wątku, który jest tworzony i uruchamiany:

using System;
using System. Gwintowanie;
przestrzeń nazw ex1
{
Program zajęć
{
public static void Write1 ()
{
Konsola. Napisz („1”);
Wątek. Sen (500);
}
static void Main (string [] args)
{
var task = nowy wątek (Write1);
zadanie. Początek() ;
dla (var i = 0; i <10; i ++)
{
Konsola. Napisz („0”);
Konsola. Pisz (zadanie. Żyje? „A”: „D”);
Wątek. Sen (150);
}
Konsola. Kluczem przeczytać() ;
}
}
}

Jedynym przykładem tego jest zapisanie „1” na konsoli. Główny wątek zapisuje „0” na konsoli 10 razy, za każdym razem po nim „A” lub „D”, w zależności od tego, czy drugi wątek jest nadal Żywy, czy Martwy.

Drugi wątek działa tylko raz i zapisuje „1”. Po półsekundowym opóźnieniu w wątku Write1 () wątek kończy się i zadanie. IsAlive w głównej pętli zwraca teraz „D.”

Pula wątków i biblioteka zadań równoległych

Zamiast tworzyć własny wątek, chyba że naprawdę musisz to zrobić, skorzystaj z puli wątków. Od .NET 4.0 mamy dostęp do biblioteki zadań równoległych (TPL). Podobnie jak w poprzednim przykładzie, znów potrzebujemy trochę LINQ, i tak, to wszystkie wyrażenia lambda.

Zadania korzystają z Pula wątków za kulisami, ale lepiej wykorzystaj wątki w zależności od użytej liczby.

Głównym przedmiotem w licencji TPL jest zadanie. Jest to klasa reprezentująca operację asynchroniczną. Najczęstszym sposobem na rozpoczęcie działania jest zadanie. Fabryka. Start Nowy jak w:

Zadanie. Fabryka. StartNew (() => DoSomething ());

Gdzie DoSomething () jest uruchamianą metodą. Możliwe jest utworzenie zadania i nie uruchamianie go natychmiast. W takim przypadku wystarczy użyć zadania w następujący sposób:

var t = new Task (() => Console. WriteLine („Hello”));
...
t. Początek();

To nie uruchamia wątku, dopóki nie zostanie wywołana funkcja .Start (). W poniższym przykładzie jest pięć zadań.

using System;
using System. Gwintowanie;
using System. Gwintowanie. Zadania;
przestrzeń nazw ex1
{
Program zajęć
{
public static void Write1 (int i)
{
Konsola. Napisz (i);
Wątek. Sen (50);
}
static void Main (string [] args)
{
dla (var i = 0; i <5; i ++)
{
wartość var ​​= i;
var runningTask = Zadanie. Fabryka. StartNew (() => Write1 (wartość));
}
Konsola. Kluczem przeczytać() ;
}
}
}

Uruchom to, a otrzymasz cyfry od 0 do 4 w losowej kolejności, takiej jak 03214. Jest tak, ponieważ kolejność wykonywania zadań jest określana przez .NET.

Być może zastanawiasz się, dlaczego potrzebna jest wartość var ​​= =. Spróbuj go usunąć i wywołać Write (i), a zobaczysz coś nieoczekiwanego, np. 55555. Dlaczego to? Jest tak, ponieważ zadanie pokazuje wartość i w czasie wykonywania zadania, a nie w momencie jego utworzenia. Tworząc nowy zmienna za każdym razem w pętli każda z pięciu wartości jest poprawnie zapisywana i pobierana.

instagram story viewer