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

TPL vs Reactive Framework

Когда вы решите использовать Rx над TPL или 2 фреймворка ортогональны?

Из того, что я понимаю, Rx в первую очередь предназначен для обеспечения абстракции по событиям и допускает композицию, но также позволяет обеспечить абстракцию по асинхронным операциям. используя перегрузки Createxx и перегрузки и отмены Fromxxx путем удаления возвращаемого IDisposable.

TPL также обеспечивает абстракцию для операций с помощью функций "Задача" и "Отмена".

Моей дилеммой является, когда использовать, какие и для каких сценариев?

4b9b3361

Ответ 1

Основная цель Rx - не предоставлять абстракции по событиям. Это лишь один из его результатов. Его основная цель - предоставить композиционную модель push для коллекций.

Реактивная структура (Rx) основана на IObservable<T>, являющемся математическим двойником IEnumerable<T>. Поэтому вместо "вытягивания" элементов из коллекции с помощью IEnumerable<T> мы можем иметь объекты, "нажатые" нам через IObservable<T>.

Конечно, когда мы действительно ищем наблюдаемые источники, события, подобные событиям, а асинхронные операции - отличные кандидаты.

Реактивная структура, естественно, требует многопоточной модели, чтобы иметь возможность наблюдать за источниками наблюдаемых данных и управлять запросами и подписками. Rx фактически использует TPL для этого.

Итак, если вы используете Rx, вы неявно используете TPL.

Вы должны использовать TPL напрямую, если хотите прямо контролировать свои задачи.

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

Ответ 2

Некоторые рекомендации, которые мне нравятся:

  • Имею ли я данные, которые я не создаю. Данные, которые поступают, когда им это нравится? Тогда RX.
  • Я получаю вычисления и должен управлять concurrency? Затем TPL.
  • Я управляю несколькими результатами и должен выбирать из них на основе времени? Тогда RX.

Ответ 3

Мне нравятся очки Bullet Scott W. Чтобы привести более конкретные примеры в Rx действительно красиво отображает

  • потребляющие потоки
  • выполнение неблокирующей асинхронной работы, например, веб-запросов.
  • потоковые события (события .net, такие как перемещение мыши или события типа сообщения служебной шины)
  • Составление "потоков" событий вместе
  • Операции стиля Linq
  • Предоставление потоков данных из общедоступного API

TPL, похоже, красиво рисует на

  • внутренняя параллелизация работы
  • выполнение неблокирующей асинхронной работы, например веб-запросов
  • выполнение рабочих потоков и продолжений

Одна вещь, которую я заметил с IObservable (Rx), заключается в том, что она становится всепроникающей. Как только вы войдете в свою базу кода, так как она, без сомнения, будет открыта через другие интерфейсы, она в конечном итоге появится повсюду в вашем приложении. Я предполагаю, что сначала это может быть страшно, но большая часть команды довольно удобна с Rx и любит работу, которую она нам спасает.

IMHO Rx будет доминирующей библиотекой по TPL, поскольку она уже поддерживается в .NET 3.5, 4.0, Silverlight 3, Silverlight 4 и Javascript. Это означает, что вам нужно научиться одному стилю, и он применим ко многим платформам.

EDIT. Я изменил свое мнение о том, что Rx доминирует над TPL. Они решают разные проблемы, поэтому на самом деле их не следует сравнивать. С .NET 4.5/С# 5.0 ключевые слова async/await свяжут нас с TPL (что хорошо). Для глубокого диска на Rx vs events vs TPL и т.д. Посмотрите первую главу моей онлайн-книги IntroToRx.com

Ответ 4

Обновление, декабрь 2016 года: Если у вас есть 30 минут, я рекомендую вам прочитать первую учетную запись Джо Даффи вместо моих спекуляций. Я думаю, что мой анализ держится хорошо, но если вы нашли этот вопрос, я настоятельно рекомендую вам видеть сообщение в блоге вместо этих ответов, потому что помимо TPL vs Rx.NET он также занимается исследовательскими проектами MS (Midori, Cosmos).

http://joeduffyblog.com/2016/11/30/15-years-of-concurrency/


Я думаю, что MS сделала большую ошибку за исправление после выхода .NET 2.0. Они ввели много разных API-интерфейсов concurrency все одновременно из разных частей компании.

  • Стивен Тууб сильно настаивал на инициативах, защищенных потоками, для замены события (которое начиналось как Future<T> и превратилось в Task<T>)
  • У MS Research были MIN-LINQ и Reactive Extensions (Rx)
  • Оборудование/встроенное хранилище cuntime (CCR) для робототехники

Тем временем многие управляемые команды API пытались жить с APM и Threadpool.QueueUserWorkItem(), не зная, выиграет ли Toub его бой, чтобы отправить Future<T>/Task<T> в mscorlib.dll. В конце концов, похоже, что они были хеджированы и отправлены как Task<T>, так и IObservable<T> в mscorlib, но не разрешали никаких других Rx API (даже не ISubject<T>) в mscorlib. Я думаю, что эта хеджирование закончилась тем, что вызвала огромное количество дублирования (более позднее) и потраченных впустую усилий внутри и вне компании.

Для дублирования см. Task vs. IObservable<Unit>, Task<T> vs. AsyncSubject<T>, Task.Run() vs. Observable.Start(). И это только верхушка айсберга. Но на более высоком уровне подумайте:

  • StreamInsight - потоки событий SQL, оптимизированные по собственному коду, но запросы событий, определенные с помощью синтаксиса LINQ
  • TPL Dataflow - построенный на TPL, встроенный параллельно Rx, оптимизированный для настройки threading parallelism, не подходит для составления запросов
  • Rx - Удивительная выразительность, но чреватая опасностью. Смешивает "горячие" потоки с IEnumerable -строчными методами расширения, что означает, что вы очень легко блокируете навсегда (вызов First() в горячем потоке никогда не возвращается). Пределы планирования (ограничение parallelism) выполняется с помощью довольно нечетных методов расширения SubscribeOn(), которые являются странно неявными и труднодоступными. Если вы начнете изучать Rx, запомните долгое время, чтобы изучить все подводные камни, которых следует избегать. Но Rx - действительно единственный вариант при составлении сложных потоков событий, или вам нужна сложная фильтрация/запрос.

Я не думаю, что у Rx есть шанс на успех при широком усыновлении, пока MS не отправит ISubject<T> в mscorlib. Что печально, потому что Rx содержит некоторые очень полезные конкретные (общие) типы, такие как TimeInterval<T> и Timestamped<T>, которые, я думаю, должны быть в Core/mscorlib, как Nullable<T>. Кроме того, System.Reactive.EventPattern<TEventArgs>.

Ответ 5

Я бы сказал, что поток данных TPL охватывает специализированный поднабор функциональности в Rx. Dataflow предназначен для обработки данных, которые могут принимать измеримое количество времени, тогда как Rx - для событий, таких как положение мыши, состояния ошибок и т.д., Когда время обработки незначительно.

Пример: ваш обработчик "подписаться" является асинхронным и в то время вы хотите не более 1 исполнителя. С Rx вам нужно блокировать, нет другого пути, потому что Rx является асинхронным и не угрожает асинхронным способом во многих местах.

.Subscribe(myAsyncHandler().Result)

Если вы не заблокируете, тогда Rx рассмотрит, что действие завершено, а обработчик все еще выполняется асинхронно.

Вы можете подумать, что если вы делаете

.ObserveOn(Scheduler.EventLoopSchedule)

чем проблема решена. Но это нарушит ваш рабочий процесс .Complete(), потому что Rx будет думать, что он будет выполнен, как только он запланирует выполнение, и вы закроете свое приложение, не дожидаясь завершения операции async.

Если вы хотите разрешить не более 4 одновременных асинхронных задач, чем Rx не предлагает ничего из коробки. Возможно, вы можете взломать что-то, выполнив свой собственный планировщик, буфер и т.д.

TPL Dataflow предлагает очень хорошее решение в ActionBlock. Он может активировать одновременные действия до определенного числа, и он понимает операции async, поэтому вызов Complete() и ожидание для Completed будет делать именно то, что вы ожидаете: ожидание завершения всех асинхронных задач.

Еще одна особенность TPL - "противодавление". Скажем, вы обнаружили ошибку в вашей процедуре обработки и вам нужно пересчитать данные за прошлый месяц. Если вы подписываетесь на свой источник с помощью Rx, а ваш конвейер содержит неограниченные буферы или ObserveOn, то у вас будет нехватка памяти в считанные секунды, потому что источник будет продолжать читать быстрее, чем обрабатывать. Даже если вы реализуете блокирующий потребитель, ваш источник может страдать от блокировки вызовов, например, если источник является асинхронным. В TPL вы можете реализовать источник как

while(...)
    await actionBlock.SendAsync(msg)

который не блокирует источник, будет ждать, пока обработчик перегружен.

В целом я обнаружил, что Rx отлично подходит для действий, которые являются временными и вычислительно светлыми. Если время обработки становится существенным, вы находитесь в мире странных побочных эффектов и эзотерической отладки.

Хорошей новостью является то, что блоки потока данных TPL играют очень хорошо с Rx. У них есть адаптеры AsObserver/AsObservable, и вы можете вставлять их в середине Rx-конвейера, когда это необходимо. Но Rx имеет гораздо больше шаблонов и вариантов использования. Поэтому мое эмпирическое правило должно начинаться с Rx и при необходимости добавлять поток данных TPL.

Ответ 6

Я сделал приложение для Windows Phone. Начинается с RX. Проблема в том, что в какой-то момент я использовал новую версию RX и угадал, что? Множество функций получило "устаревший" атрибут. Итак, я начал с TPL, и теперь у меня смешанный проект с обоими. Мой совет: если вы используете много асинхронных веб-вызовов, лучше использовать TPL. Как уже написано, RX использует TPL, поэтому почему бы не использовать TPL с самого начала.