Ответ
Parallel — это класс в пространстве имён System.Threading.Tasks, предоставляющий упрощённый API для параллельного выполнения циклов (for, foreach) и независимых действий над коллекциями данных. Он абстрагирует ручное управление потоками, используя пул потоков .NET.
Основные методы:
Parallel.For— параллельный аналог циклаfor.Parallel.ForEach— параллельный аналог циклаforeach.Parallel.Invoke— параллельное выполнение набора действий (Action).
Когда использовать? Идеально для CPU-bound задач, где есть большой объём однотипных вычислений, которые можно выполнять независимо (например, обработка пикселей изображения, симуляции, математические расчёты).
Пример: параллельная обработка коллекции.
using System.Threading.Tasks;
var data = Enumerable.Range(1, 10000).ToList();
var results = new double[data.Count];
// Последовательная обработка
foreach (var item in data)
{
results[item - 1] = PerformHeavyCalculation(item);
}
// Параллельная обработка с Parallel.For
Parallel.For(0, data.Count, i =>
{
// Каждая итерация может выполняться в отдельном потоке
results[i] = PerformHeavyCalculation(data[i]);
});
// Параллельная обработка с Parallel.ForEach
Parallel.ForEach(data, (item, state, index) =>
{
results[index] = PerformHeavyCalculation(item);
});
static double PerformHeavyCalculation(int input)
{
// Имитация ресурсоёмкой операции
return Math.Sqrt(Math.Pow(input, 3)) * Math.Tan(input);
}
Критически важные моменты:
- Потокобезопасность: Тело цикла (
Action) выполняется в нескольких потоках одновременно. Доступ к общим ресурсам (коллекциям, статическим полям) должен быть синхронизирован (например, с помощьюlock,ConcurrentBag,Interlocked).var sharedSum = 0; object lockObj = new object(); Parallel.For(0, 1000, i => { // НЕПРАВИЛЬНО: sharedSum += i; // Race condition! // ПРАВИЛЬНО: lock (lockObj) { sharedSum += i; } // ИЛИ ЛУЧШЕ (для простых операций): Interlocked.Add(ref sharedSum, i); }); - Порядок выполнения: Итерации выполняются не по порядку. Нельзя полагаться на последовательность.
- Неподходящие сценарии: Для I/O-bound операций (чтение файлов, сетевые запросы)
Parallelблокирует потоки пула. Вместо этого используйте асинхронное программирование (Task.WhenAll,Parallel.ForEachAsyncв .NET 6+). - Накладные расходы: Для очень маленьких коллекций или простых операций оверхед на распараллеливание может превысить выгоду. Всегда замеряйте производительность.