Už async/await I/O operacijoms, .NET pateikia Task Parallel Library (TPL) dėl CPU-susietos lygiagretizmo — skaičiavimų vykdymo keliuose branduoliuose. Pagrindinė išskirtis: async/await yra I/O konkurencija (neblokuojantys laukai), o Task.Run, Parallel ir PLINQ yra CPU-intensyvaus darbo paralelizavimui.
Kritinė išskirtis: konkurencija vs lygiagretumas
async/await → I/O-bound concurrency. Frees the thread during waits (DB, network).
Does NOT add CPU parallelism.
Parallelism → CPU-bound work spread across MULTIPLE CORES (computation, processing).
Use Task.Run, Parallel.For/ForEach, PLINQ.
Task.Run — CPU darbo nukreipimas į foninio gijos siūlą
// run a CPU-intensive computation on a thread pool thread (don't block the caller)
int result = await Task.Run(() => ExpensiveComputation());
// run multiple in parallel and combine
var tasks = items.Select(item => Task.Run(() => Process(item)));
var results = await Task.WhenAll(tasks); // wait for all
Task.Run planuoja darbą gijų fondo siūle — naudokite ją CPU-susieto skaičiavimo paralelizavimui (NE I/O, kur async/await jau pakankama be papildomų gijų).
Parallel ir PLINQ — duomenų lygiagretumas
// Parallel.For/ForEach — process a collection across cores
Parallel.ForEach(items, item => Process(item)); // automatically uses multiple cores
Parallel.For(0, 1000, i => Compute(i));
// PLINQ — parallel LINQ
var results = data.AsParallel().Where(x => IsValid(x)).Select(Transform).ToList();
Parallel.For/ForEach ir PLINQ (.AsParallel()) automatiškai paskirsto darbą per branduolius — puiku CPU-sunaudam tiems duomenų apdorojimams. (Verta tik tikrai CPU-susieto, didelio masto darbo — yra pridėtinių išlaidų.)
Gijų saugumas (sunkiausia dalis)
// parallel code accessing SHARED state needs synchronization or thread-safe types
lock (_lock) { _counter++; } // lock for mutual exclusion
Interlocked.Increment(ref _counter); // lock-free atomic
var dict = new ConcurrentDictionary<string, int>(); // thread-safe collection
Kodėl tai svarbu
Supratimas apie Užduotis ir lygiagretumą už async/await ribų yra svarbi aukšto lygio žinybė greitai veikiančioms C# programoms kurti, o kritinė išskirtis tarp I/O konkurencijos ir CPU lygiagretizmo yra pagrindinis suvokimas — dažna painiavos priežastis. async/await tvarkosi su I/O-susieta konkurencija (gijų atlaisvinimas laukų metu), bet nėra CPU lygiagretizmo, o CPU-susietas darbas (skaičiavimai, duomenų apdorojimas) naudojasi tikru lygiagretizmu per branduolius per Task.Run (CPU darbo nukreipimą į gijų fondo siūlus), Parallel.For/ForEach ir PLINQ (.AsParallel()).
Žinojimas, kuris įrankis tinka — async/await I/O, TPL lygiagretizmo įrankiai CPU-susieto darbo — yra esmingas veiksmingam našumo optimizavimui, nes naudojant netinkamą (pvz., tikintis, kad async greitins skaičiavimus, arba kuriant gijas I/O, kurį async efektyviai tvarkosi) yra neveiksminga.
Lygiai svarbu suprasti gijų saugumą: lygiagretusis kodas, kurie pasiekia bendrą būseną, reikalingas sinchronizaciją (lock, Interlocked atominiam operacijai, arba saugias gijas rinkinius kaip ConcurrentDictionary) siekiant išvengti lenktyniauti — kritinė teisingumas priežiūra lygiagretaus kodo.
Supratimas apie I/O-vs-CPU išskyrimą, lygiagretizmo įrankius (Task.Run, Parallel, PLINQ) ir gijų-saugumo reikalavimus yra vertinga teisingam, greitam konkurentiniam ir lygiagrečiam C# parašymui.
Kadangi šiuolaikinės programos dažnai reikalingos tiek I/O konkurenciją ir CPU lygiagretumą, ir kadangi pasirinkti tinkamą metodą ir teisingai tvarkytis gijų saugumu yra tai, kas daro lygiagretų kodą veiksmingu ir teisingą, tai yra svarbi, dažnai aktuali aukšto lygio žinybė našumo jautriems C# plėtojimams.
