Подходит ли ThreadPool для этого сценария потоков? - PullRequest
4 голосов
/ 03 июня 2010

У меня есть сценарий, который я пытаюсь превратить в более отзывчивый пользовательский интерфейс, предварительно выбирая некоторые подэлементы результатов, прежде чем они действительно потребуются пользователю, если это возможно. Мне неясно, как лучше подходить к потокам, поэтому я надеюсь, что кто-то может дать какой-то совет.

Сценарий

Существует форма поиска (.NET rich client), которая позволяет пользователю выбрать учетную запись для данного клиента. Пользователь ищет заданный текст, чтобы найти коллекцию клиентов, которые затем отображаются в таблице результатов. Затем, когда пользователь выбирает клиента, список учетных записей для этого клиента ищется и отображается во второй сетке для выбора пользователя, чтобы создать окончательный контекст (который является учетной записью) для открытия.

Существующая система

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

Цель

Чего я хочу добиться, так это начать извлекать счета для первых N клиентов, прежде чем пользователь выберет их ... Где N - количество элементов, отображаемых в сетке.

Когда пользователь прокручивает сетку, вновь отображаемые элементы будут добавлены в «очередь» для извлечения.

Вопросы

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

Ответы [ 3 ]

2 голосов
/ 03 июня 2010

Да, пул потоков - хороший выбор, возможно, за библиотекой BackgroundPacker или .NET4 TaskParallel.

Но вы не можете (не должны) «поднять» поток ThreadPool, но я не думаю, что это все равно будет полезно.

Что вам, вероятно, следует сделать, это использовать потокобезопасную очередь (из первых N элементов) и использовать более 2 потоков для обработки очереди. Когда элемент выбран и еще не обработан, вы перемещаете его вверх или сразу запускаете отдельный поток.

1 голос
/ 05 июня 2010

Посредством обновления / решения ... Я следовал * решению Хенка (вроде), так что я сохраняю очередь объектов рабочих элементов, но все еще обрабатываю их с помощью ThreadPool. Выбранные элементы «выталкиваются», помещая их в начало очереди (а не в конец) [примечание: для этого нужна специальная коллекция].

Следующее может описать это подробно (вместо кода)

  • Изменено Customer, чтобы сохранить свойство IList<Account> с именем KnownValues ​​, а также объект, используемый для блокировки с именем KnownValuesSyncObject (поскольку я хочу, чтобы KnownValues ​​были нулевыми, когда они отсутствуют. пока не известно).
  • Форма поиска поддерживает переменную экземпляра Deque<CustomerAccountLoadingWorkItem> (из PowerCollections )
  • A CustomerAccountLoadingWorkItem содержит ссылку на клиента, для которого он предназначен, а также на ManualResetEvent дескриптор, с которым он был создан.
  • Чтобы начать загрузку только для видимых элементов (т. Е. Не прокручивать с экрана), я использовал ответы из моего другого поста , чтобы использовать виртуализацию данных в качестве механизма организации очередей CustomerAccountLoadingWorkItem, поскольку каждая «страница» была загружена , Сразу после добавления в очередь рабочих элементов задача добавляется в очередь ThreadPool. Контекстом / состоянием для вызова ThreadPool.QueueUserWorkItem была моя очередь _accountLoadingWorkItems.
  • Делегат WaitCallback, запущенный ThreadPool, взял переданную ему очередь рабочего элемента, затем (с помощью блокировок) снял с обработки верхний элемент (если его не было, затем сразу же вернулся); затем обработал этот элемент. Используемая функция была статической функцией как часть CustomerAccountLoadingWorkItem, так что она могла получить доступ к своему частному состоянию только для чтения (то есть, Customer и ManualResetEvent)
  • В конце обработки функция статической обработки также устанавливает Customer.KnownValues ​​(используя для блокировки KnownValuesSyncObject).
  • Когда пользователь выбрал значение в сетке «Клиенты», в его уже отдельном потоке (через BackgroundWorker), если Customer.KnownValues еще не заполнен (то есть он, вероятно, где-то находится в очереди), он добавляет новый CustomerAccountLoadingWorkItem. в очередь рабочих элементов (но вверху !!! [именно поэтому требовалась Deque]), а также добавляет новую задачу обработки в ThreadPool. Затем, поскольку он создал рабочий элемент, он вызывает ManaulResetEvent.WaitOne(), чтобы вызвать ожидание завершения задачи пула потоков.

Надеюсь, это имело смысл ...

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

В целом, я, безусловно, сделал то, что должно было быть легкой задачей, несколько сложнее, и если бы я мог использовать Framework 4, я бы наверняка посмотрел на путь TPL.

0 голосов
/ 03 июня 2010

Если вариант .NET 4, могу ли я порекомендовать новую коллекцию ConcurrentStack.

http://msdn.microsoft.com/en-us/library/dd267331(v=VS.100).aspx

Вы можете добавить все элементы, которые хотите предварительно выбрать, и, если элемент выбран пользователем, вы можете поместить этот выбор в стек, сделав его следующим экземпляром для извлечения. Это прекрасно работает с новыми PLINQ и TPL и использует новые улучшения ThreadPool в .NET 4.

http://channel9.msdn.com/shows/Going+Deep/Erika-Parsons-and-Eric-Eilebrecht--CLR-4-Inside-the-new-Threadpool/

...