Как реактивные рамки, PLINQ, TPL и параллельные расширения связаны друг с другом?


по крайней мере, с момента выпуска .NET 4.0 Microsoft, похоже, приложила много усилий для поддержки параллельного и асинхронного программирования, и, похоже, появилось много API и библиотек вокруг этого. Особенно в последнее время постоянно упоминаются следующие причудливые имена:

  • Реактивной Базы,
  • PLINQ (параллельный LINQ),
  • TPL (параллельная библиотека задач) и
  • Параллельного Расширения.

теперь все они, похоже, являются продуктами Microsoft, и все они, похоже, нацелены на сценарии асинхронного или параллельного программирования для .NET. но не совсем ясно, что каждый из них на самом деле и как они связаны друг с другом. Некоторые из них могут быть на самом деле то же самое.

в нескольких словах, может кто-нибудь прояснить, что к чему?

2 62

2 ответа:

PLINQ (Parallel Linq) - это просто новый способ писать регулярные запросы Linq, чтобы они выполнялись параллельно-другими словами, платформа автоматически позаботится о выполнении вашего запроса через несколько потоков, чтобы они заканчивались быстрее (т. е. с использованием нескольких ядер процессора).

например, предположим, что у вас есть куча строк, и вы хотите, чтобы получить все те, которые начинаются с буквы "А". Вы могли бы написать ваш запрос это:

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"));

это все, что вам нужно сделать, чтобы превратить обычный запрос в параллельный, который работает на нескольких ядрах. Довольно аккуратно.


The TPL (параллельная библиотека задач) является своего рода дополнением к PLINQ, и вместе они составляют Параллельные Расширения. В то время как PLINQ в значительной степени основан на A функциональное стиль программирования с нет побочные эффекты, Побочные эффекты-это именно то, для чего предназначен 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. Есть еще несколько, из конечно, но это были те, о которых вы спрашивали!

Мне нравится ответ Аарона, но я бы сказал, что Rx и TPL решают разные проблемы. Часть того, что команда TPL добавила, - Это примитивы потоков и значительные улучшения в строительных блоках среды выполнения, таких как ThreadPool. И все, что вы перечисляете, построено поверх этих примитивов и функций времени выполнения.

но TPL и Rx решают две разные проблемы. TPL работает лучше всего, когда программа или алгоритм "тянет & queuing". Rx выделяется, когда программа или алгоритм должен "реагировать" на данные из потока (например, ввод мышкой или при получении потока сообщений от конечной точки, как в WCF).

вам понадобится концепция "единицы работы" от TPL, чтобы выполнять работу, такую как файловая система, итерация по коллекции или ходьба по иерархии, такой как организационная диаграмма. В каждом из этих случаев программист может рассуждать об общем объеме работы, работа может быть разбита на куски определенного размера (задачи), а в случае ведения расчетов по иерархии задачи могут быть "скованы" вместе. Таким образом, некоторые типы работ поддаются модели TPL "иерархия задач" и извлекают выгоду из улучшений сантехники, таких как отмена (см. Видео Канала 9 на CancellationTokenSource). TPL также имеет множество ручек для специализированных доменов, таких как обработка данных в режиме реального времени.

RX будет то, что большинство разработчиков должны в конечном итоге с помощью. Это то, как приложения WPF могут "реагировать" на внешние сообщения, такие как внешние данные (поток IM сообщения клиенту IM) или внешний ввод (например, пример перетаскивания мыши, связанный с Aaronaught). Под одеялом RX использует потоковые примитивы ЛПУ/ОУЗ, коллекции ориентирована на многопотоковое исполнение с ТПЛ/ОУЗ и динамических объектов, как класса ThreadPool. На мой взгляд, Rx - это "самый высокий уровень" программирования для выражения ваших намерений.

может ли средний разработчик обернуть свою голову вокруг набора намерений, которые вы можете выразить с помощью Rx, еще предстоит увидеть. :)

но я думаю, в ближайшие пару лет TPL против Rx будет следующей дискуссией, такой как LINQ-to-SQL против Entity Framework. Есть два варианта API в одном домене и специализируются для разных сценариев, но перекрываются во многих отношениях. Но в случае TPL & Rx они фактически знают друг о друге, и есть встроенные адаптеры для создания приложений и использования обеих фреймворков вместе (например, подача результатов из цикла PLINQ в поток IObservable Rx). Для людей, которые ничего не сделали параллельное программирование существует тонна обучения, чтобы получить до скорости.

обновление: я использую как TPL, так и RxNet в своей обычной работе в течение последних 6 месяцев (из 18 месяцев с момента моего первоначального ответа). Мои мысли о выборе TPL и / или RxNet в службе WCF среднего уровня (enterprise LOB service):http://yzorgsoft.blogspot.com/2011/09/middle-tier-tpl-andor-rxnet.html