TPL DataFlow против BlockingCollection

Я понимаю, что BlockingCollection лучше всего подходит для шаблона потребитель/производитель. Однако когда мне следует использовать ActionBlock из библиотеки TPL DataFlow?

Мое первоначальное понимание заключается в том, что для операций ввода-вывода сохраните BlockingCollection, в то время как операции с интенсивным использованием ЦП лучше всего подходят для ActionBlock. Но я чувствую, что это не вся история... Любое дополнительное понимание?


person poy    schedule 16.01.2014    source источник
comment
BlockingCollection не лучше для ввода-вывода — на самом деле он хуже из-за отсутствия поддержки асинхронности.   -  person Cory Nelson    schedule 16.01.2014


Ответы (2)


Поток данных TPL лучше подходит для проектирования на основе акторов. Это означает, что если вы хотите объединить производителей и потребителей в цепочку, с TDF будет намного проще.

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

Вы также можете очень легко установить ограниченную емкость и степень параллелизма.

TL;DR: BlockingCollection — это простой и универсальный инструмент. TPL Dataflow намного надежнее, но может быть излишним или плохо подходить для конкретных задач.

person i3arnon    schedule 16.01.2014
comment
@ i3amon Можете ли вы дать рекомендации или примеры? Как TPL Dataflow может быть излишним и неподходящим? Надежность не повредит даже в простых ситуациях. Есть ли проблема с производительностью? Спасибо. - person silvalli; 25.07.2019
comment
@silvalli TPL Dataflow заставляет вас действовать определенным образом, BlockingCollection открыт для ваших действий. Проблема с BlockingCollection заключается в том, что он только синхронный. Но в настоящее время у вас есть библиотека System.Threading.Channels, чтобы избежать этого. Так что это зависит от того, хотите ли вы структурированный или неструктурированный параллелизм. - person i3arnon; 26.07.2019
comment
@silvalli Теперь я буду избегать BlockingCollection почти во всех случаях. - person i3arnon; 26.07.2019

Не уверен, что повторное использование слова «блок» вызывает здесь путаницу. Это очень разные вещи.

Вы правы, BlockingCollection хорошо подходит для ситуации производителя-потребителя, поскольку она будет блокировать попытку чтения из нее до тех пор, пока данные не будут доступны. Однако BlockingCollection не является частью потока данных TPL. Он был представлен в .NET 4.0 как один из новых типов коллекций, безопасных для потоков.

Однако ActionBlock — это тип «блока», определенный потоком данных TPL, и его можно использовать для выполнения действия. Блок в этом смысле больше относится к его использованию как части потока данных.

Потоки данных, как определено в потоке данных TPL, состоят из блоков трех основных типов. Из документации:

Библиотека потоков данных TPL состоит из блоков потока данных, представляющих собой структуры данных, которые буферизуют и обрабатывают данные. TPL определяет три типа блоков потока данных: исходные блоки, целевые блоки и блоки распространения. Исходный блок действует как источник данных и может быть прочитан. Целевой блок действует как приемник данных и может быть записан. Блок распространителя действует как исходный блок и как целевой блок, и его можно читать и записывать. TPL определяет интерфейс System.Threading.Tasks.Dataflow.ISourceBlock для представления источников, System.Threading.Tasks.Dataflow.ITargetBlock для представления целей и System.Threading.Tasks.Dataflow.IPropagatorBlock для представления распространителей. IPropagatorBlock наследуется как от ISourceBlock, так и от TargetBlock. Библиотека потоков данных TPL предоставляет несколько предопределенных типов блоков потоков данных, реализующих интерфейсы ISourceBlock, ITargetBlock и IPropagatorBlock. Эти типы блоков потока данных описаны в этом документе в разделе Предопределенные типы блоков потока данных.

ActionBlock — это тип ITargetBlock, который принимает ввод, выполняет действие и затем останавливается.

Чтобы ответить на ваш первый вопрос, я думаю, что вы можете использовать BlockingCollection, когда ваш процесс прост. Вы бы использовали поток данных TPL, когда ваш процесс более сложный, и в этом случае вам, вероятно, не понадобится BlockingCollection.

Примеры проблемы «производитель-потребитель» с использованием BlockingCollection приведены здесь: Consumer-problem.aspx?Redirected=true" rel="nofollow">http://blogs.msdn.com/b/csharpfaq/archive/2010/08/12/blocking-collection-and-the-producer-consumer- Problem.aspx?Redirected=true и здесь: http://programmerfindings.blogspot.co.uk/2012/07/producer-consumer-problem-using-tpl-and.html

Ни один из них не использует Dataflow. Здесь есть пример использования Dataflow:

http://msdn.microsoft.com/en-us/library/hh228601(v=vs.110).aspx

Кроме того, я настоятельно рекомендую прочитать документацию TPL Dataflow здесь:

http://msdn.microsoft.com/en-us/library/hh228601(v=vs.110).aspx

если вы реализуете что-то сложное.

person bornfromanegg    schedule 09.02.2014