Подтвердить что ты не робот

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

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

  • Reactive Framework,
  • PLINQ (Parallel LINQ),
  • TPL (параллельная библиотека задач) и
  • Параллельные расширения.

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

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

4b9b3361

Ответ 1

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

Например, скажем, что у вас есть куча строк, и вы хотите получить все те, которые начинаются с буквы "A". Вы можете написать свой запрос следующим образом:

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 в значительной степени основан на функциональном стиле программирования без побочных эффектов, побочные эффекты - именно то, для чего нужен 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. Конечно, есть еще несколько, но это были те, о которых вы просили!

Ответ 2

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

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

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

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

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

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

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