Должен ли я использовать ThreadPools или параллельную библиотеку задач для операций, связанных с IO
В одном из моих проектов, который является своего рода агрегатором, я анализирую каналы, подкасты и так далее из интернета.
Если я использую последовательный подход, учитывая большое количество ресурсов, требуется довольно много времени, чтобы обработать их все (из-за проблем с сетью и тому подобного);
foreach(feed in feeds)
{
read_from_web(feed)
parse(feed)
}
Поэтому я хочу реализовать параллелизм и не могу решить, следует ли мне в основном использовать ThreadPools для обработки с рабочими потоками или просто полагаться на TPL, чтобы отсортировать его.
ThreadPools наверняка будут обработайте работу для меня с рабочими потоками, и я получу то, что ожидаю (и в многоядерных процессорных средах другие ядра также будут использоваться).
Но я все еще хочу рассмотреть TPL, поскольку это рекомендательный метод, но я немного обеспокоен этим. Прежде всего, я знаю, что TPL использует ThreadPools, но добавляет дополнительный уровень принятия решений. Меня больше всего беспокоит состояние, при котором присутствует одноядерная среда. Если я не ошибаюсь TPL начинается с числа рабочие потоки равны количеству доступных процессорных ядер в самом начале. Я действительно боюсь, что TPL даст аналогичные результаты последовательному подходу для моего случая, связанного с IO.
Итак, для операций, связанных с IO (в моем случае чтение ресурсов из интернета), лучше всего использовать ThreadPools и контролировать вещи, или лучше просто полагаться на TPL? Может ли TPL также использоваться в сценариях, связанных с IO?
Обновление: моя главная забота-это ... на одноядерный процессор среда ОСАГО, ведут себя как последовательный подход или он все еще будет предлагать параллелизм? Я уже читаю параллельное программирование с Microsoft .NET и поэтому книгу , но не смог найти точного ответа на этот вопрос.
Примечание: это перефразирование моего предыдущего вопроса [ возможно ли использовать параллелизм потоков и параллелизм вместе?Что было совершенно неправильно сформулировано.
6 ответов:
Поэтому я вместо этого решил написать тесты для этого и посмотреть их на практических данных.
Легенда Теста
- Itr: Итерация
- Seq: Последовательный Подход.
- PrlEx: Параллельные Расширения-Parallel.ForEach
- TPL: параллельная библиотека задач
- TPool: ThreadPool
Результаты Испытаний
одноядерный процессор [Win7-32] -- работает под управлением VMWare --
Test Environment: 1 physical cpus, 1 cores, 1 logical cpus. Will be parsing a total of 10 feeds. ________________________________________________________________________________ Itr. Seq. PrlEx TPL TPool ________________________________________________________________________________ #1 10.82s 04.05s 02.69s 02.60s #2 07.48s 03.18s 03.17s 02.91s #3 07.66s 03.21s 01.90s 01.68s #4 07.43s 01.65s 01.70s 01.76s #5 07.81s 02.20s 01.75s 01.71s #6 07.67s 03.25s 01.97s 01.63s #7 08.14s 01.77s 01.72s 02.66s #8 08.04s 03.01s 02.03s 01.75s #9 08.80s 01.71s 01.67s 01.75s #10 10.19s 02.23s 01.62s 01.74s ________________________________________________________________________________ Avg. 08.40s 02.63s 02.02s 02.02s ________________________________________________________________________________
одноядерный процессор [WinXP] -- работает под управлением VMWare --
Test Environment: 1 physical cpus, NotSupported cores, NotSupported logical cpus. Will be parsing a total of 10 feeds. ________________________________________________________________________________ Itr. Seq. PrlEx TPL TPool ________________________________________________________________________________ #1 10.79s 04.05s 02.75s 02.13s #2 07.53s 02.84s 02.08s 02.07s #3 07.79s 03.74s 02.04s 02.07s #4 08.28s 02.88s 02.73s 03.43s #5 07.55s 02.59s 03.99s 03.19s #6 07.50s 02.90s 02.83s 02.29s #7 07.80s 04.32s 02.78s 02.67s #8 07.65s 03.10s 02.07s 02.53s #9 10.70s 02.61s 02.04s 02.10s #10 08.98s 02.88s 02.09s 02.16s ________________________________________________________________________________ Avg. 08.46s 03.19s 02.54s 02.46s ________________________________________________________________________________
двухъядерный процессор [Win7-64]
Test Environment: 1 physical cpus, 2 cores, 2 logical cpus. Will be parsing a total of 10 feeds. ________________________________________________________________________________ Itr. Seq. PrlEx TPL TPool ________________________________________________________________________________ #1 07.09s 02.28s 02.64s 01.79s #2 06.04s 02.53s 01.96s 01.94s #3 05.84s 02.18s 02.08s 02.34s #4 06.00s 01.43s 01.69s 01.43s #5 05.74s 01.61s 01.36s 01.49s #6 05.92s 01.59s 01.73s 01.50s #7 06.09s 01.44s 02.14s 02.37s #8 06.37s 01.34s 01.46s 01.36s #9 06.57s 01.30s 01.58s 01.67s #10 06.06s 01.95s 02.88s 01.62s ________________________________________________________________________________ Avg. 06.17s 01.76s 01.95s 01.75s ________________________________________________________________________________
четырехъядерный процессор [Win7-64] -- поддерживается гиперпоточность --
Test Environment: 1 physical cpus, 4 cores, 8 logical cpus. Will be parsing a total of 10 feeds. ________________________________________________________________________________ Itr. Seq. PrlEx TPL TPool ________________________________________________________________________________ #1 10.56s 02.03s 01.71s 01.69s #2 07.42s 01.63s 01.71s 01.69s #3 11.66s 01.69s 01.73s 01.61s #4 07.52s 01.77s 01.63s 01.65s #5 07.69s 02.32s 01.67s 01.62s #6 07.31s 01.64s 01.53s 02.17s #7 07.44s 02.56s 02.35s 02.31s #8 08.36s 01.93s 01.73s 01.66s #9 07.92s 02.15s 01.72s 01.65s #10 07.60s 02.14s 01.68s 01.68s ________________________________________________________________________________ Avg. 08.35s 01.99s 01.75s 01.77s ________________________________________________________________________________
Обобщение
Независимо от того, работаете ли вы в одноядерной среде или многоядерной, параллельные расширения, TPL и ThreadPool ведут себя одинаково и дают приблизительные результаты.
- Тем не менее TPL имеет преимущества , такие как простая обработка исключений, поддержка отмены и способность легко возвращать результаты задачи . Хотя параллельные расширения также являются еще одной жизнеспособной альтернативой.
Запуск тестов самостоятельно
Вы можете скачать исходный кодздесь и запустить его самостоятельно. Если вы можете опубликовать результаты, я добавлю их также.
Обновление: исправлена исходная ссылка.
Если вы пытаетесь максимизировать пропускную способность для задач, связанных с IO, вы абсолютно должен объедините традиционные API модели асинхронной обработки (APM) с вашей работой на основе TPL. API APM-это единственный способ разблокировать поток ЦП, пока асинхронный обратный вызов ввода-вывода находится в ожидании. TPL предоставляет вспомогательный метод
TaskFactory::FromAsync
для помощи в объединении кода APM и TPL.Проверьте этот раздел .NET SDK на MSDN под названием TPL и традиционный .NET Асинхронное программирование для получения дополнительной информации о том, как объединить эти две модели программирования для достижения асинхронной нирваны.
Вы правы, что TPL действительно удаляет некоторые элементы управления, которые у вас есть, когда вы создаете свой собственный пул потоков. Но это правильно только в том случае, если вы не хотите копать глубже. TPL позволяет создавать длительные задачи, которые не являются частью пула потоков TPL и могут хорошо служить вашей цели. Опубликованная книга, которая является свободным чтениемпараллельное программирование с Microsoft .NET даст вам гораздо больше информации о том, как предполагается использовать TPL. У вас всегда есть возможность дать Паралле.Для, задачи явные параметры, сколько потоков должно быть выделено. Кроме того, вы можете заменить планировщик TPL на свой собственный, если хотите получить полный контроль.
Вы можете назначить свой собственныйпланировщик задач задаче TPL. По умолчанию Работа кража один довольно умный, хотя.
Я действительно боюсь, что TPL даст аналогичные результаты последовательному подходу для моего случая, связанного с IO.
Я думаю, что так и будет. Что такое узкое место? Это разбор или загрузка? Многопоточность не очень поможет вам при загрузке из интернета.
Я бы использовал параллельную библиотеку задач для обрезки, применения маски или эффектов для загруженных изображений, вырезания некоторого образца из подкаста и т. д. Он более масштабируемый.
Но это не будет на порядок ускоряться. Проведите свой ресурсы для реализации некоторых функций, тестирования.ПС. "Ничего себе моя функция исполняется за 0.7 с вместо 0.9";)
Если вы распараллелите свои вызовы на URL-адреса, я думаю, что это улучшит ваше приложение, даже если у него есть только одно ядро. Взгляните на этот код:
var client = new HttpClient(); var urls = new[]{"a", "url", "to", "find"}; // due to the EAP pattern, this will run in parallel. var tasks = urls.Select(c=> client.GetAsync(c)); var result = Tasks.WhenAll(task).ContinueWith(a=> AnalyzeThisWords(a.Result)); result.Wait(); // don't know if this is needed or it's correct to call wait
Разница между многопоточностью и асинхронностью в этом случае заключается в том, как выполняется обратный вызов/завершение.
При использовании EAP количество задач не связано с количеством потоков.
Поскольку вы полагаетесь на Задачу GetAsync, http-клиент использует сетевой поток (сокет, tcp-клиент или что-то еще) и сигнализирует его чтобы вызвать событие, когда выполняется BeginRead/EndRead. Таким образом, никакие нити не вовлечены в этот момент.
После вызова завершения может быть создан новый поток, но это зависит от TaskScheduler (используется в вызове GetAsync/ContinueWith call), чтобы создать новый поток, использовать существующий поток или встроить задачу, чтобы использовать вызывающий поток.
Если
AnalyzeThisWords
блокируется слишком много времени, то вы начинаете получать узкие места, поскольку "обратный вызов" на ContinueWith выполняется из пула потоков работник.