2010-09-14 2 views
5

В настоящее время у меня есть раздел кода, который должен содержать около 7 запросов веб-сервисов для различных поставщиков данных. Каждый вызов занимает несколько секунд, поэтому я хотел бы запускать их параллельно, чтобы ускорить работу.Использование параллельных расширений .Net (Parallel.Invoke) для множественных асинхронных вызовов?

Я завернул свои 7 звонков в Parallel.Invoke, который отлично работает при одновременном запуске нескольких вещей, но на 2-ядерном сервере он будет выполнять только 2 за один раз, по одному на ядро. Поскольку все, что я делаю, ждёт, когда вызовы веб-службы возвращаются, я бы хотел, чтобы он забрал все 7 и дождался их возвращения.

Нет ли способа сделать это? Или, может быть, мой подход неправильный? Возможно, мне нужно создать асинхронные вызовы для веб-служб? Но потом, как ждать, пока они все вернутся, прежде чем двигаться дальше?

ответ

5

но на 2 ядра сервера, он будет выполнять только 2 в то время, один на каждое ядро ​​

Я бы вопрос этот - Parallel.Invoke обычно работать гораздо больше задач, чем ядра в системе ,

Если вы используете асинхронные вызовы вызова метода, я бы рекомендовал использовать Task.Factory.FromAsync(...) для генерации семи различных задач.

Это обеспечивает гибкость выполнения другой работы во время выполнения задач, а затем вызывает Task.WaitAll (или Task.WaitAny), когда вы решите использовать результаты.

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

+2

У меня создалось впечатление, что он действительно хотел, чтобы все они закончили, прежде чем продолжить. –

+1

@Steven: Что он может делать через Task.WaitAll - но он может выполнять другую работу, пока он ждет, если он доступен, если это вариант. Случаи, подобные этому, часто работают с Task.WaitAny, так как вы обычно можете начать часть работы, как только некоторые из задач завершатся - редко вам нужно 7 разных результатов для любой обработки ... –

+0

Вы правильно, это тоже будет работать и более гибко, чем я предлагал. –

0

Чтобы увеличить уровень параллелизма, вы можете указать ParallelOptions. Значение по умолчанию разумно для задач с привязкой к процессору, но вы имеете дело с привязанными к I/O, поэтому имеет смысл переопределить это поведение.

+0

Я думал, что увеличение уровня параллелизма только доходит до максимально допустимого параллелизма? т. е. если у вас есть 8 ядер, вы можете установить уровень параллелизма на что-либо ... но превышать 8 ничего не сделает ... – puffpio

+0

@puffpio: все, что он говорит, это: «MaxDegreeOfParallelism ограничивает количество параллельных операций, выполняемых вызовами Parallel, которые передаются этому экземпляру ParallelOptions к установленному значению, если оно положительное. Если MaxDegreeOfParallelism равно -1, тогда нет предела помещается на количество одновременно выполняемых операций ». –

+0

Да, это меня смущает, так как он говорит «предел», который для меня означает, что он не выйдет за пределы количества ядер, которые у вас есть. Я говорю это, потому что страница на Parallel.Invoke говорит: «Обратите внимание, что с помощью Invoke() вы просто указываете, какие действия вы хотите запускать одновременно, а среда выполнения обрабатывает все детали планирования потоков, включая автоматическое масштабирование числа ядер на хост-компьютер." – puffpio

1

Для этого не нужно использовать Parallel.Invoke. Вы можете продолжить и выдавать несколько асинхронных запросов (т. Е. HttpWebRequest.BeginGetResponse()). Что касается уведомления, когда все они завершены, у вас есть несколько вариантов. Простым способом было бы инициализировать CountdownEvent до того, как вы выберете первый запрос, а затем подождите, пока главный поток будет ждать этого события после его запроса. Асинхронные методы обратного вызова каждый сигнализируют об этом событии по мере их завершения. Таким образом, вы гарантируете, что все запросы будут выполнены до продолжения основного потока.

+1

Но TPL так много, как APM. Было бы неплохо, если бы у нас было лучшее из обоих миров. –

+0

Использование Task.Factory.StartAsync обеспечивает лучшее из обоих миров ... без необходимости отслеживать с CountdownEvent и т. Д. –

+0

Мне нужно более внимательно изучить TPL. –

0

Я собираюсь скопировать a response that I made to another question verbatim, потому что это одинаково, если не больше, применимо здесь.


Вы просто не можете победить асинхронную модель программирования (APM), когда дело доходит до производительности ввода/вывода. В любое время, когда вы можете использовать его, вы должны быть. К счастью, параллельная библиотека задач (TPL) поставляется с поддержкой для объединения работы APM в микс с «чистыми» задачами TPL через the FromAsync factory method.

Ознакомьтесь с разделом .NET SDK на MSDN под названием TPL and Traditional .NET Asynchronous Programming для получения дополнительной информации о том, как объединить эти две модели программирования для достижения асинхронной нирваны.

Смежные вопросы