2010-08-31 3 views
1

Что бы быть лучшим подходом для реализации задач с помощью ключа, который работает следующим образом: -Реализация «только один из» и «не в параллельной» семантике с параллельной библиотекой задач

Вариант 1) Только один из этих ключ никогда не ожидается. Может использоваться, например, из ASP.NET MVC, чтобы помещать в очередь один рендер для миниатюрного изображения независимо от того, сколько раз поражает URL-адрес изображения. Только один запускается, все остальные запросы ждут завершения этого.

Вариант 2) Все элементы с одним и тем же ключом должны выполняться последовательно. Можно использовать, например, чтобы гарантировать, что операции, которые извлекают файл из хранилища резервных копий в локальный кеш, не все пытаются одновременно загрузить файл в кеш. Вариант 1 является частным случаем, когда последующие действия с одним и тем же ключом просто отбрасываются (как правило, сохраняется только проверка файла).

У меня есть существующий WorkQueue, который обрабатывает оба этих случая (а также состояние квартиры, параметры ThreadPriority и максимальные степени параллелизма). TPL, по-видимому, является лучшим решением для замены этого и приведет к улучшенным вариантам отмены.

Вложенные задачи с продолжением выглядят обнадеживающими, но сохранение словаря текущих задач queue'd вскоре становится беспорядочным между классами TaskFactory и TaskScheduler. Наследование из задачи также проблематично, поскольку ни TaskFactory, ни TaskScheduler не являются обобщенными в Task.

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

Кто-нибудь реализовал что-либо подобное этому с помощью TPL, и если да, то вы взяли в своих классах Task, TaskScheduler и TaskFactory?

+0

Неверный вопрос, oops –

ответ

1

Может быть, один способ, которым я могу думать

  1. Создание класса-оболочки - говорят KeyProcessor в очереди пункты для ключа.
  2. Метод KeyProcessor.Run() будет способен к любой семантике очередей, в которой вы нуждаетесь. По сути, он будет искать внутреннюю очередь для любой ожидающей работы, а затем продолжать делать ее последовательно.
  3. Поддержание словаря объектов KeyProcessor.
  4. Для любой новой задачи зайдите в словарь для того же ключа. Если этого не существует, добавьте его. Остановите задачу на нем. Если он не работает, то планируйте его с помощью TPL, используя метод Run как действие.
  5. Используйте ContinueWith для планирования задачи поддержки - например, всякий раз, когда Завершение выполнения KeyProcessor.Run завершено, задачи продолжения могут проверять, запланированы ли какие-либо задачи для одного и того же ключа (поскольку он завершен) и запустить его снова ИЛИ удалить из словаря.

Все выше было бы сложно от точки синхронизации потока, а не для нескольких интересных коллекций, присутствующих в пространстве имен System.Collections.Concurrent. Это сделало бы эту логику намного проще.Например, ConcurrentDictionary.GetOrAdd позволит искать и/или добавлять объект KeyProcessor потокобезопасным способом.

+0

Пользовательская фабрика задач, использующая Continuations, смогла решить эту проблему. Сообщение в блоге: http://blog.abodit.com/2010/09/constrained-parallelism-for-the-task-parallel-library/. Я дам вам счет ответа, так как ваше предложение близко. –

1

Эта проблема аналогична той, которую я решил в ReactiveXaml, хотя мои и мемуаризованные предыдущие запросы. Взгляните на код для QueuedAsyncMRUCache (и его blog entry) - этот код объединяет TPL с Reactive Extensions, чтобы сделать это, но он делает важную гарантию того, что второй запрос для того же ключа будет блокироваться на первом в полете, вместо того, чтобы выдать другой.

+1

Спасибо, интересно, но не совсем то, что мне нужно. Я должен добавить, что я хочу иметь возможность запускать и забывать, а также «огонь и ждать» по любой добавленной задаче. Я также хочу, чтобы ключи были удалены, как только последний выполнил. например обновляя время последнего посещения для пользователя на веб-сайте: пять одновременных обращений сворачиваются к одной записи, но позже запись записывается. –

+0

Возможно, по крайней мере, вы можете получить вдохновение от того, как я его реализовал –

+0

Как ни странно, я в конечном итоге реализовал то, что вы выбрали для варианта № 2 для проекта: https://gist.github.com/2877c8181d5ae4c8ac02 –

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