Parallel Extensions это небольшое дополнение к библиотеке System.Threading, которое позволяет на высоком уровне выполнять задачи на всех доступных ядрах/процессорах.
История
Библиотека Parallel Extensions (PE) — совместный проект команды .Net и Microsoft Research — впервые увидела свет 29 ноября 2007 года. Она создана для того, чтобы разработчики могли пользоваться современными многоядерными архитектурами, не утруждая себя трудоемким управлением потоками. Программы, написанные с применением библиотеки, автоматически используют все доступные ядра системы. Если же программа будет запущена на старом одноядерном компьютере, то выполнение будет происходить последовательно, практически без потерь в производительности. Таким образом, использование PE раскрывает все преимущества многоядерных технологий, сохраняя работоспособность на одноядерных системах.
Последнее обновление библиотеки было в июне 2008 года. Сейчас она имеет статус Community Technology Preview и, скорее всего, войдет в 4 версию .Net.
Состав библиотеки
PE состоит из трех основных компонентов:
* Task Parallel Library (TPL) — предоставляет такие императивные методы, как Parallel.For, Parallel.Foreach и Parallel.Invoke для выполнения параллельных вычислений. Вся работа по созданию и завершению потоков, в зависимости от имеющихся процессоров выполняется библиотекой автоматически.
* Parallel LINQ (PLINQ) — надстройка над LINQ to Objects и LINQ to XML, позволяющая выполнять параллельные запросы. В большинстве случаев достаточно в начале запроса написать AsParallel() для того, чтобы все последующие операторы выполнялись параллельно. Внутренне использует TPL.
* Coordination Data Structures (CDS) — набор структур, который используется для синхронизации и координации выполнения параллельных задач.
Перейдём к примеру:
PHP код:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlClient;
using System.IO;
using System.Threading;
class Program
{
private static int nbFiles;
private static int nbMatchFiles;
private const String dirPath = @"D:\_Dev";
private const String pattern = "public";
static void Main(string[] args)
{
Console.WriteLine("Searching for : " + pattern);
nbFiles = 0;
nbMatchFiles = 0;
DateTime start = DateTime.Now;
Console.WriteLine("Search using Standard Processing");
SearchForStandard(dirPath, pattern, true);
Console.WriteLine(string.Format("Total files : {0}", nbFiles));
Console.WriteLine(string.Format("found in files : {0}", nbMatchFiles));
Console.WriteLine(string.Format("Search Duration : {0}", DateTime.Now.Subtract(start).ToString()));
Console.ReadKey();
}
private static void SearchForStandard(string path, string text, bool recurse)
{
foreach (String file in Directory.GetFiles(path, "*.*"))
{
Interlocked.Increment(ref nbFiles);
FindInFile(file, text);
}
if (recurse)
{
foreach (String dir in Directory.GetDirectories(path))
{
SearchForStandard(dir, text, recurse);
}
}
}
private static void FindInFile(string csFilePath, string text)
{
if (File.ReadAllText(csFilePath).IndexOf(text) >= 0)
Interlocked.Increment(ref nbMatchFiles);
}
}
Результат:
Код:
Searching for : public
Search using Standard Processing
Total files : 23210
found in files : 6689
Search Duration : 00:01:17.6940000
Теперь с использованием Parallel Extensions:
PHP код:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlClient;
using System.IO;
using System.Threading;
class Program
{
private static int nbFiles;
private static int nbMatchFiles;
private const String dirPath = @"F:\_Dev";
private const String pattern = "public";
static void Main(string[] args)
{
Console.WriteLine("Searching for : " + pattern);
nbFiles = 0;
nbMatchFiles = 0;
DateTime start = DateTime.Now;
Console.WriteLine("Search using Parallel Processing");
SearchForParallel(dirPath, pattern, true);
Console.WriteLine(string.Format("Total files : {0}", nbFiles));
Console.WriteLine(string.Format("found in files : {0}", nbMatchFiles));
Console.WriteLine(string.Format("Search Duration : {0}", DateTime.Now.Subtract(start).ToString()));
}
private static void SearchForParallel(string path, string text, bool recurse)
{
Parallel.ForEach(Directory.GetFiles(path, "*.cs"), csFilePath =>
{
Interlocked.Increment(ref nbFiles);
FindInFile(csFilePath, text);
});
if (recurse)
Parallel.ForEach(Directory.GetDirectories(path),
dirName => SearchForParallel(dirName, text, recurse));
}
private static void FindInFile(string csFilePath, string text)
{
if (File.ReadAllText(csFilePath).IndexOf(text) >= 0)
Interlocked.Increment(ref nbMatchFiles);
}
}
И результат:
Код:
Search using Parallel Processing
Total files : 6708
found in files : 6059
Search Duration : 00:00:02.3510000
Как видим выигрыш в производительности есть, и немалый а от нас потребовалось просто написать Parallel.ForEach вместо обычного ForEach, всё остальное PE делает за нас ;-)
Скачать Parallel Extensions для .Net 3.5