c # задание регулирования нескольких очередей - PullRequest
12 голосов
/ 25 марта 2012

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

  • очередь 1 -> 3 потока;
  • Очередь 2 -> 6 потоков;

Вид системы задач. Мне удалось реализовать это самостоятельно, используя старый старый код на c # (он же System.Threading.Thread, lock и queue), который работает более 1 года. Тем не менее, я продолжаю читать статьи о чудесах TaskFactory и TaskScheduler, о возможности этого со встроенными классами в .NET, но мне не удалось найти пример, чтобы доказать это. Я хотел бы проверить это и сравнить с тем, что у меня есть сейчас, чтобы увидеть, работает ли он лучше, и если да, то заменить его.

Более того, я могу жить без необходимости ограничивать / устанавливать количество параллельных потоков для каждой очереди, пока я могу получить guarantee, что если элемент, предназначенный для очереди # 2, выполняется немедленно, даже если очередь # 1 выполняется при полной загрузке.

Итак, мой вопрос - есть ли что-то в .net 4 и более, кто-то может указать мне образец? Я ищу одну целую неделю и не смог найти что-то подходящее.

Ответы [ 2 ]

8 голосов
/ 25 марта 2012

Это на самом деле довольно тривиально, используя TPL и новые коллекции в System.Collections.Concurrent.

Для ваших нужд BlockingCollection<T> это то, что я бы порекомендовал.По умолчанию он использует ConcurrentQueue<T> в качестве базового хранилища, которое идеально подходит для того, что вы хотите.

var queue = new BlockingCollection<Message>();

Чтобы установить некоторый код, работающий с этими сообщениями, и контролировать, сколько из них может выполнятьсяпараллельно это так просто:

//Set max parallel Tasks
var options = new ParallelOptions
{
    MaxDegreeOfParallelism = 10
};

Parallel.ForEach(queue.GetConsumingEnumerable(), options, msg =>
{
    //Do some stuff with this message
});

Так что же здесь происходит?Ну ...

Вызов GetConsumingEnumerable() будет фактически блокироваться, пока в queue не будет что-то потреблять.Это здорово, потому что не требуется никакого дополнительного кода для сигнализации о том, что новая работа готова к выполнению.Скорее, когда queue заполняется, новая задача с вашим (анонимным) делегатом будет запущена с элементом.

Объект ParallelOptions позволяетВы можете контролировать, как работает Parallel.ForEach.В этом случае вы говорите, что никогда не хотите, чтобы одновременно выполнялось более 10 задач. Важно отметить, что Tasks! = Threads .Детали мрачны, но, разумеется, под капотом происходит много оптимизаций.Это все подключаемо, но это не для слабонервных.

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

3 голосов
/ 25 марта 2012

Вы можете попробовать создать эквивалент LimitedConcurrencyLevelTaskScheduler, упомянутый в в этом примере , или заглянуть в планировщик приоритетов, упомянутый здесь .

...