максимальная степень параллелизма потока данных tpl

Я создаю конвейер, используя поток данных TPL. Скажем, у меня есть конвейер, состоящий из четырех блоков TransformBlock.

GetDataFromDatabase
ProcessData1
ProcessData2
SendDataToRestService

Каждый из них может (вероятно, будет) длительной операцией. GetDataFromDatabase, вероятно, в основном будет ждать ответа базы данных, SendDataToRestService будет ждать ответа службы. ProcessData 1 и 2 будут долго выполняющимися локальными процессами с интенсивным использованием ЦП.

Теперь я намеревался установить максимальную степень параллелизма на каждом из моих блоков в соответствии с количеством ядер на машине (которое, вероятно, будет равно 4).

Но мне приходит в голову, что это означает, что он будет делать сразу 4 GetDataFromDatabases, и 4 сразу ProcessData1, и 4 сразу ProcessData2, и 4 SendDataToRestService сразу. Это означало бы, что у меня потенциально может быть 16 потоков, работающих одновременно. Добавьте к этому, что на самом деле у меня есть 3 разных потока, делающих одно и то же одновременно.

ВОПРОС: Как лучше всего подойти к этому, чтобы получить наилучшую производительность? Из того, что я прочитал, если я попытаюсь сделать слишком много, я могу снизить производительность из-за переключения контекста. Есть ли лучший подход, или это «высоси и посмотри»?


person bornfromanegg    schedule 09.02.2014    source источник
comment
Мне кажется, что последние 3 шага можно сделать за один ActionBlock. Нет необходимости в трубопроводе.   -  person usr    schedule 09.02.2014
comment
На самом деле я не понимаю, зачем вообще нужно больше одного ActionBlock. Просто разместите в нем все рабочие элементы и используйте асинхронный рабочий делегат. Вы можете установить степень параллелизма таким образом.   -  person usr    schedule 09.02.2014
comment
Возможно, вы правы, но, простите меня, если я что-то упустил, но не могли бы вы сказать это о любом конвейере? В таком случае, какой в ​​них смысл?   -  person bornfromanegg    schedule 09.02.2014
comment
Я новичок в потоке данных TPL, но ценность связывания блоков вместе, похоже, заключается в составлении разных типов блоков с разным поведением. Если вам просто нужен одношаговый конвейер, пусть будет так.   -  person usr    schedule 09.02.2014


Ответы (2)


Во-первых, как предложил @usr, ваш случай подходит для одного ActionBlock. Смысл связывания нескольких блоков состоит в том, чтобы составить блоки разных типов с разными конфигурациями. Например, если у вас был один шаг с MaxDegreeOfParallelism из 1, а другой с 10.

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

Из Как указать степень параллелизма в Блок потока данных

Поскольку свойство MaxDegreeOfParallelism представляет максимальную степень параллелизма, блок потока данных может выполняться с меньшей степенью параллелизма, чем указано вами. Блок потока данных может использовать меньшую степень параллелизма для удовлетворения своих функциональных требований или для учета нехватки доступных системных ресурсов. Блок потока данных никогда не выбирает большую степень параллелизма, чем вы указали.

person i3arnon    schedule 09.02.2014
comment
Привет. Я уже думал об уменьшении количества блоков, которые у меня были, но не был уверен, что у меня есть веская причина. Мне понравился аспект «единицы работы». Однако я думаю, что вижу, что в данном случае это может быть не лучший выход, поэтому я упрощу его. Сказав это, я несколько упростил свой сценарий для целей вопроса - возможно, я слишком упростил его :-). У меня определенно есть требования, чтобы некоторые из моих блоков обрабатывались только по одному, что они и делают в настоящее время. Спасибо за помощь. - person bornfromanegg; 10.02.2014
comment
@ user1158174 конечно, в любое время. - person i3arnon; 10.02.2014

Я думаю, что здесь имело бы смысл объединить два блока, привязанных к процессору, в один. Таким образом, вы можете настраивать блоки с разными характеристиками отдельно.

Если бы это было невозможно (это могло произойти, например, если блоки, привязанные к ЦП, не находились рядом друг с другом в конвейере), то, скорее всего, было бы нормально установить MaxDegreeOfParallelism каждого блока, привязанного к ЦП, на ProcessorCount. Пул потоков умен и не будет использовать слишком много потоков, если только он не сочтет это выгодным. Хотя я думаю, что использование блокирующего кода ввода-вывода в других блоках (или других частях программы) может привести к путанице, поэтому я бы предложил использовать асинхронный ввод-вывод.

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

person svick    schedule 10.02.2014