Я пытаюсь лучше понять всю концепцию параллельной обработки и настроил тестовые примеры. Поиграв с тестами, я вижу, что использование вызовов методов Async в Dataflow ActionBlock
(или TransformBlock
) не влияет положительно на производительность, а просто усложняет код. Правильно ли я предполагаю, что если я использую блоки потока данных, код внутри них не обязательно должен быть асинхронным, поток данных сам сделает его асинхронным. Или я упустил суть?
Поток данных TPL и вызовы асинхронных методов
Ответы (2)
TPL Dataflow не поддерживает параллелизм или распараллеливание (хотя вы можете использовать такие вещи, как ActionBlock
для распараллеливания его обработки), это то, что параллельный или параллельный код использует для передачи данных. Помимо прочего, это механизм передачи сообщений - своего рода альтернатива общим данным. Совместно используемые данные при использовании несколькими потоками требуют дорогостоящей синхронизации. Передача сообщений, если все сделано правильно, не требует синхронизации, потому что данные, с которыми нужно работать, инкапсулируются в сообщение, которое «отправляется» коду, который будет с ними работать.
TPL Dataflow - это то, что вы можете использовать, если у вас есть конкретный дизайн. Если вы специально не реализуете что-то вроде программирования на основе актеров или передача сообщений или неблокирующие сценарии производителя / потребителя, тогда поток данных TPL, скорее всего, усложнит ситуацию.
Если вы думаете, что можете разработать такую систему, есть несколько полезных ресурсов по пониманию потока данных TPL (TDF), например видео Стивена Туба (члена параллельной группы Microsoft), а также Страница MSDN потока данных.
ОБНОВИТЬ:
Вы можете установить максимальную степень параллелизма для блока, но установка его выше, чем количество процессоров или ядер, часто приводит к обратным результатам. Предполагается, что каждое выполняемое действие более или менее связано с ЦП (использование ЦП на 100% во время выполнения). Если действия тратят много времени на ожидание (ожидание дескриптора ожидания, ожидание сообщений в насосе сообщений - что не является нормальным для действия, но для потока пользовательского интерфейса и т. Д.), То степень параллелизма выходит за рамки количество процессоров может иметь смысл (хотя это будет сложно настроить). Когда у вас действительно выполняется больше действий, чем процессоров, которые привязаны к процессору, вы действительно начинаете загружать ОС. ОС хочет отдать процессорное время каждому потоку (или каждому действию в данном случае), потому что он «работает». Когда не хватает процессоров для обхода, ОС начинает выполнять многозадачность с вытеснением, циклически отдавая процессорное время каждому активному потоку. Каждый раз, когда ОС отводит процессор от одного потока и передает его другому, это называется переключением контекста. . Это действительно дорого (в диапазоне 2000-8000 циклов процессора). Итак, ОС действительно тратит все свое время на переключение контекста, а не на выполнение ваших действий.
Если ваши действия действительно асинхронны, то степень параллелизма блока не имеет значения, потому что распараллеливание выполняет что-то другое. Но возникает та же проблема, ваши асинхронные действия выполняются без проверки, и вы рискуете перегрузить ОС из-за степени переключения контекста, которую вы вводите. Я бы серьезно подумал о том, чтобы не выполнять асинхронные действия из-за отсутствия контроля.
ThreadPool.QueueUserWorkItem,
не TPL ...) Но, если вы говорите TPL, что вам нужна максимальная степень параллелизма, вы говорите ему, что все должно иметь свой собственный поток (ну, вы просите, чтобы все выполнялось одновременно - в настоящее время единственный способ сделать это - дать чему-то отдельную тему).
- person Peter Ritchie; 07.09.2012
MaxDegreeOfParallelism
на неограниченный не означает, что каждый элемент будет обрабатываться в собственном потоке, что действительно было бы ужасно неэффективным. Это означает, что он будет использовать столько потоков, сколько ThreadPool позволит ему, что в большинстве случаев будет около 1 на ядро.
- person svick; 07.09.2012
Parallel.ForEach
с перегрузкой ParallelOptions
.
- person Peter Ritchie; 07.09.2012
TPL Dataflow не подходит для всех видов параллельной обработки, а также не сделает ваш код волшебным образом быстрее.
Основная идея TDF заключается в том, что у вас есть блоки, которые выполняют свою работу независимо. Это означает, что работа для каждого блока может выполняться в отдельном потоке, поэтому распараллеливание кода с использованием TDF в некоторых случаях может быть очень простым.
Это может быть особенно полезно, если код внутри блока использует какой-то ресурс, которым нельзя делиться. Таким образом, вы можете максимально эффективно использовать этот общий ресурс, поскольку обработка этого блока не зависит от других блоков.
В общем, TDF наиболее подходит, если ваш код похож на конвейер: элемент поступает, обрабатывается на этапе 1, затем на этапе 2,… и, наконец, он поступает на вывод. Хотя сети с потоками данных могут быть намного сложнее. Но вы не должны пытаться форсировать это, если то, что вы хотите сделать, не подходит для TDF, вы правы в том, что вы просто усложняете свой код без всякой пользы.