PLINQ (Parallel Linq) - это просто новый способ написания обычных запросов Linq, чтобы они выполнялись параллельно - другими словами, Framework автоматически позаботится о выполнении вашего запроса в нескольких потоках, чтобы они заканчиваются быстрее (то есть с использованием нескольких процессорных ядер).
Например, допустим, у вас есть куча строк, и вы хотите получить все те, которые начинаются с буквы «А». Вы можете написать свой запрос так:
var words = new[] { "Apple", "Banana", "Coconut", "Anvil" };
var myWords = words.Select(s => s.StartsWith("A"));
И это прекрасно работает. Однако если у вас есть 50 000 слов для поиска, вы можете воспользоваться тем фактом, что каждый тест является независимым, и разделить его на несколько ядер:
var myWords = words.AsParallel().Select(s => s.StartsWith("A"));
Это все, что вам нужно сделать, чтобы превратить обычный запрос в параллельный, который выполняется на нескольких ядрах. Довольно аккуратно.
TPL (библиотека параллельных задач) является своего рода дополнением к PLINQ, и вместе они составляют параллельные расширения. В то время как PLINQ в значительной степени основан на стиле функционального программирования с побочными эффектами no , побочные эффекты - это как раз то, для чего предназначен TPL. Если вы хотите на самом деле работать параллельно, а не просто искать / выбирать вещи параллельно, используйте TPL.
TPL - это, по существу, класс Parallel
, который предоставляет перегрузки For
, Foreach
и Invoke
. Invoke
немного похож на постановку в очередь задач в ThreadPool
, но немного проще в использовании. ИМО, более интересные биты это For
и Foreach
. Например, предположим, у вас есть целая куча файлов, которые вы хотите сжать. Вы можете написать обычную последовательную версию:
string[] fileNames = (...);
foreach (string fileName in fileNames)
{
byte[] data = File.ReadAllBytes(fileName);
byte[] compressedData = Compress(data);
string outputFileName = Path.ChangeExtension(fileName, ".zip");
File.WriteAllBytes(outputFileName, compressedData);
}
Опять же, каждая итерация этого сжатия полностью независима от любой другой. Мы можем ускорить это, выполнив несколько из них одновременно:
Parallel.ForEach(fileNames, fileName =>
{
byte[] data = File.ReadAllBytes(fileName);
byte[] compressedData = Compress(data);
string outputFileName = Path.ChangeExtension(fileName, ".zip");
File.WriteAllBytes(outputFileName, compressedData);
});
И снова, это все, что нужно для распараллеливания этой операции. Теперь, когда мы запустим наш метод CompressFiles
(или как мы его назовем), он будет использовать несколько ядер ЦП и, вероятно, закончится в два раза или в 1/4 раза.
Преимущество этого по сравнению с простым бросанием всего этого в ThreadPool
состоит в том, что на самом деле работает синхронно . Если бы вы использовали ThreadPool
вместо (или просто Thread
экземпляров), вам нужно было бы найти способ узнать, когда все задачи завершены, и хотя это не ужасно сложно, это то, что многие люди, как правило, портят или, по крайней мере, имеют проблемы. Когда вы используете класс Parallel
, вам не нужно об этом думать; многопоточность скрыта от вас, все это обрабатывается за кулисами.
Реактивные расширения (Rx) - это совсем другое животное. Это другой способ думать об обработке событий. Об этом действительно много материала, но, если коротко, вместо того, чтобы подключать обработчики событий к событиям, Rx позволяет вам обрабатывать последовательности событий как ... ну, последовательности (IEnumerable<T>
). Вы получаете возможность обрабатывать события итеративным способом, а не запускать их асинхронно в случайные моменты времени, когда вам необходимо постоянно сохранять состояние, чтобы обнаружить серию событий, происходящих в определенном порядке.
Один из самых крутых примеров, которые я нашел для Rx, это здесь . Перейдите к разделу «Linq to IObservable», где он реализует обработчик перетаскивания, который обычно является проблемой в WPF, всего за 4 строки кода. Rx дает вам состав событий, чего у вас нет на самом деле с обычными обработчиками событий, и фрагменты кода, подобные этим, также просты для рефакторинга в классы поведения, которые вы можете использовать в любом месте.
И это все. Вот некоторые из функций кулера, которые доступны в .NET 4.0. Конечно, есть еще несколько, но о них вы спрашивали!