Все, кто программирует на C#, так или иначе использовали оператор foreach.
Этот оператор используется как правило для итерации коллекции и применяет вложенные операторы к каждому элементу коллекции. Добавлять или удалять элементы коллекции при этом не рекомендуется, так как возможны побочные эффекты.
Но, что, если нам необходимы длительные вычисления над элементами последовательности и полученные результаты не зависят друг от друга?
В .NET Framework 4 появились интересные возможности параллельности: Parallel.ForEach и Parallel LINQ (PLINQ).
* В этой статье я не рассматриваю такие вещие как async-await и другие вещи, касающиеся .NET Framework 4.5.
Простейший форма метода ForEach выгляди следующим образом:
-
public static ParallelLoopResult ForEach<TSource>(IEnumerable<TSource> source, Action<TSource> body)
-
{
-
if (source == null)
-
{
-
throw new ArgumentNullException("source");
-
}
-
if (body == null)
-
{
-
throw new ArgumentNullException("body");
-
}
-
return ForEachWorker<TSource, object>(source, s_defaultParallelOptions, body, null, null, null, null, null, null);
-
}
Этот метод разбивает данные на части и оперирует над элементами в различных потоках.
Метод возвращает сведения о состоянии цикла.
Пример абстрактного коня в вакууме (как всегда - из рабочего проекта):
-
public void Start()
-
{
-
Parallel.ForEach(_components,
-
component =>
-
{
-
Console.WriteLine("Component loaded: {0}", component.Value.Description);
-
foreach (var value in component.Value.Execute())
-
_storage.Save(XElement.Parse(value));
-
});
-
}
В этом коде происходит вызов множества компонент (каждая компонента - сборка .NET), каждый из которых загружает множество Xml документов, и сохраняет их в некое абстрактное хранилище.
При этом сохранение происходит асинхронно, то есть без задержек.
-
async Task Save(XElement message);