programare pe calculator termenul "thread" este scurt pentru thread-ul de execuție, în care un procesor urmează o cale specificată prin codul dvs. Conceptul de a urma mai mult de un thread simultan introduce subiectul multi-tasking și multi-threading.
O aplicație are unul sau mai multe procese în ea. Gândiți-vă la un proces ca la un program care rulează pe computer. Acum, fiecare proces are unul sau mai multe fire. O aplicație de joc ar putea avea un fir pentru a încărca resurse de pe disc, alta pentru a face AI și alta pentru a rula jocul ca server.
În .NET / Windows, sistemul de operare alocă timp procesorului unui thread. Fiecare thread urmărește gestionarea excepțiilor și prioritatea la care rulează și are undeva să salveze contextul thread până când rulează. Contextul firelor este informația pe care firul trebuie să o reia.
Multi-sarcini cu fire
Firele preiau un pic de memorie și crearea lor durează puțin, așa că, de obicei, nu vrei să folosești multe. Amintiți-vă, ei concurează pentru timpul procesorului. Dacă computerul are mai multe procesoare, atunci Windows sau .NET ar putea rula fiecare thread pe un procesor diferit, dar dacă mai multe fire rulează pe același procesor, apoi doar unul poate fi activ la un moment dat și trecerea firelor de schimb timp.
CPU procesează un thread pentru câteva milioane de instrucțiuni, apoi trece la un alt thread. Toate registrele procesorului, punctul de execuție și stiva actuală a programului trebuie să fie salvate undeva pentru primul thread și apoi restabilite din altă parte pentru următorul thread.
Crearea unui fir
În Sistemul de spații de nume. Filetat, veți găsi tipul de fir. Firul constructorului (ThreadStart) creează o instanță a unui thread. Cu toate acestea, în recent C # cod, este mai probabil să treceți într-o expresie lambda care apelează metoda cu orice parametri.
Dacă nu sunteți sigur expresii lambda, ar putea merita să verificați LINQ.
Iată un exemplu de thread creat și pornit:
folosind Sistem;
folosind System. Filetat;
spațiu de nume ex1
{
Programul clasei
{
public static void Write1 ()
{
Consolă. Scrieți ('1');
Fir. Somn (500);
}
static void Main (string [] args)
{
var task = new Thread (Write1);
sarcină. Start() ;
for (var i = 0; i <10; i ++)
{
Consolă. Scrieți ('0');
Consolă. Scrieți (sarcină. Este in viata? 'ANUNȚ') ;
Fir. Somn (150);
}
Consolă. ReadKey ();
}
}
}
Tot acest exemplu este să scrieți „1” în consolă. Firul principal scrie un "0" pe consolă de 10 ori, de fiecare dată urmat de un "A" sau "D", în funcție de faptul că celălalt fir este încă viu sau mort.
Celălalt thread rulează o singură dată și scrie un „1.” După o întârziere de jumătate de secundă în firul Write1 (), firul se termină și Task. IsAlive în bucla principală returnează acum „D.”
Biblioteca de fire și bibliotecă paralelă cu activități
În loc să-ți creezi propriul thread, cu excepția cazului în care ai nevoie într-adevăr să faci asta, folosește un pool de fire. De la .NET 4.0, avem acces la biblioteca paralelă cu activități (TPL). Ca și în exemplul anterior, din nou avem nevoie de un pic de LINQ și, da, este vorba de expresii lambda.
Sarcini utilizează Piscina de fire în spatele scenei, dar utilizează mai bine firele în funcție de numărul utilizat.
Obiectul principal din TPL este o Sarcină. Aceasta este o clasă care reprezintă o operație asincronă. Cea mai obișnuită modalitate de a începe lucrările este cu Task. Fabrică. StartNew ca în:
Sarcină. Fabrică. StartNew (() => DoSomething ());
Unde DoSomething () este metoda rulată. Este posibil să creați o sarcină și să nu o executați imediat. În acest caz, utilizați Task astfel:
var t = new Task (() => Consola. WriteLine ( "Bună ziua"));
...
T. Start();
Aceasta nu pornește firul până când nu este apelat .Start (). În exemplul de mai jos, sunt cinci sarcini.
folosind Sistem;
folosind System. Filetat;
folosind System. Filetat. Sarcini;
spațiu de nume ex1
{
Programul clasei
{
public static void Write1 (int i)
{
Consolă. Scrieți (i);
Fir. Somn (50);
}
static void Main (string [] args)
{
for (var i = 0; i <5; i ++)
{
valoarea var = i;
var runningTask = Task. Fabrică. StartNew (() => Write1 (valoare));
}
Consolă. ReadKey ();
}
}
}
Rulează asta și obții cifrele 0 până la 4 într-o ordine aleatorie, cum ar fi 03214. Asta deoarece ordinea executării sarcinilor este determinată de .NET.
S-ar putea să vă întrebați de ce este nevoie de valoarea var = i. Încercați să-l îndepărtați și să apelați Write (i) și veți vedea ceva neașteptat ca 55555. De ce asta? Se datorează faptului că sarcina arată valoarea lui i în momentul în care sarcina este executată, nu atunci când sarcina a fost creată. Prin crearea unui nou variabil de fiecare dată în buclă, fiecare dintre cele cinci valori este corect stocată și ridicată.