Πέρα από το / για I/O, το .NET παρέχει την για — εκτέλεση υπολογισμών σε πολλαπλούς πυρήνες. Η κύρια διάκριση: το / είναι για I/O concurrency (μη-blocking waits), ενώ το , το , και το PLINQ είναι για παραλληλοποίηση CPU-intensive work.
Πέρα από το / για I/O, το .NET παρέχει την για — εκτέλεση υπολογισμών σε πολλαπλούς πυρήνες. Η κύρια διάκριση: το / είναι για I/O concurrency (μη-blocking waits), ενώ το , το , και το PLINQ είναι για παραλληλοποίηση CPU-intensive work.
asyncawaitasyncawaitTask.RunParallelasync/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.
// 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 ανατίθεται στη δουλειά ένα thread pool thread — χρησιμοποιήστε το για παραλληλοποίηση CPU-bound computation (ΟΧΙ για I/O, όπου το async/await είναι ήδη επαρκές χωρίς επιπλέον threads).
// 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 και το PLINQ (.AsParallel()) κατανέμουν αυτόματα τη δουλειά σε πυρήνες — εξαιρετικό για CPU-heavy processing ανεξάρτητων στοιχείων. (Αξίζει μόνο για όντως CPU-bound, μεγάλη δουλειά — υπάρχει overhead.)
// 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
Η κατανόηση του Tasks και του parallelism πέρα από το async/await είναι σημαντική γνώση επιπέδου senior για τη δημιουργία performant C# εφαρμογών, και η κρίσιμη διάκριση μεταξύ I/O concurrency και CPU parallelism είναι η κύρια ιδέα — ένα συνηθισμένο σημείο σύγχυσης. Το async/await χειρίζεται I/O-bound concurrency (απελευθέρωση threads κατά τα waits) αλλά ΔΕΝ προσθέτει CPU parallelism, ενώ το CPU-bound work (υπολογισμοί, data processing) ωφελείται από πραγματικό parallelism σε πυρήνες μέσω Task.Run (offloading CPU work σε thread pool threads), Parallel.For/ForEach, και PLINQ (.AsParallel()).
Η γνώση ποιο εργαλείο ταιριάζει — async/await για I/O, τα TPL parallelism tools για CPU-bound work — είναι απαραίτητη για αποτελεσματική performance optimization, καθώς η χρήση του λάθους (π.χ. αναμονή ότι το async επιταχύνει τον υπολογισμό, ή δημιουργία threads για I/O που το async χειρίζεται αποτελεσματικά) είναι αναποτελέσματη.
Εξίσου σημαντική είναι η κατανόηση του thread safety: ο παράλληλος κώδικας που προσπελαύνει shared state χρειάζεται synchronization (lock, Interlocked για atomic operations, ή thread-safe collections όπως ConcurrentDictionary) για αποφυγή race conditions — ένα κρίσιμο correctness concern στον παράλληλο κώδικα.
Η κατανόηση της I/O-vs-CPU distinction, τα parallelism tools (Task.Run, Parallel, PLINQ), και τις thread-safety requirements είναι πολύτιμη για τη σγραφή correct, performant concurrent και parallel C#.
Επειδή οι σύγχρονες εφαρμογές συχνά χρειάζονται τόσο I/O concurrency όσο και CPU parallelism, και επειδή η επιλογή της σωστής προσέγγισης και ο σωστός χειρισμός του thread safety είναι αυτά που κάνουν τον παράλληλο κώδικα effective και correct, αυτή είναι σημαντική, συχνά σχετική senior knowledge για performance-sensitive C# development.