Индикатор выполнения и несколько потоков, развязка GUI и логики - какой шаблон проектирования будет лучшим? - PullRequest
5 голосов
/ 14 февраля 2009

Я ищу шаблон дизайна, который бы соответствовал моему дизайну приложения.

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

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

Я не хочу создавать несколько индикаторов выполнения. Вместо этого я хотел бы иметь единый индикатор выполнения, который информирует о глобальном прогрессе. В настоящий момент я могу думать о MVC и Observer / Observable, но это немного размыто :) Может быть, кто-то может указать мне правильное направление, спасибо.

Ответы [ 4 ]

6 голосов
/ 15 февраля 2009

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

Алгоритм состоял из 6 различных шагов. Каждый шаг имел временные характеристики, которые серьезно зависели от A) базовых обрабатываемых данных, не только от «количества» данных, но также от «типа» данных и B) 2 шагов, масштабируемых очень хорошо с увеличением числа процессоров, 2 шага выполнялись в 2 потока, а 2 шага были фактически однопоточными.

Эффективное сочетание данных оказало гораздо большее влияние на время выполнения каждого шага, чем количество ядер.

Решение, которое окончательно взломало его, было действительно довольно простым. Я сделал 6 функций, которые анализировали набор данных и пытались предсказать фактическое время выполнения каждого шага анализа. Эвристика в каждой функции анализировала как анализируемые наборы данных, так и количество процессоров. Основываясь на данных времени выполнения с моего собственного 4-ядерного компьютера, каждая функция в основном возвращала ожидаемое количество миллисекунд, на моем компьютере .

f1 (..) + f2 (..) + f3 (..) + f4 (..) + f5 (..) + f6 (..) = общее время выполнения в миллисекундах

Теперь, учитывая эту информацию, вы можете эффективно узнать, какой процент от общего времени выполнения каждого шага должен занять. Теперь, если вы говорите, что step1 должен занимать 40% времени выполнения, вам нужно выяснить, как генерировать 40 1% событий из этого алгоритма. Скажем, цикл for обрабатывает 100 000 элементов, возможно, вы могли бы сделать:

for (int i = 0; i < numItems; i++){
     if (i % (numItems / percentageOfTotalForThisStep) == 0) emitProgressEvent();
     .. do the actual processing ..
}

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

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

Теперь среднестатистический читатель SO может задаться вопросом, почему, черт возьми, кто-то потратил неделю, чтобы сделать плавный индикатор прогресса. Функция была запрошена главным продавцом, и я полагаю, что он использовал ее на совещаниях по продажам для получения контрактов. Деньги говорят;)

2 голосов
/ 15 февраля 2009

В ситуациях с потоками или асинхронными процессами / задачами, подобными этим, я считаю полезным иметь абстрактный тип или объект в основном потоке, который представляет (и в идеале инкапсулирует) каждый процесс. Таким образом, для каждого рабочего потока предположительно будет объект (давайте назовем его Operation) в главном потоке для управления этим рабочим, и, очевидно, будет какая-то структура в виде списка для хранения этих операций.

Где это применимо, каждая Операция предоставляет методы запуска / остановки для своего работника, а в некоторых случаях - например, ваши - числовые свойства, представляющие ход и ожидаемое общее время или работу задачи данной Операции. Единицы не обязательно должны быть основаны на времени, если вы знаете, что будете выполнять 6230 вычислений, вы можете просто думать об этих свойствах как о подсчете вычислений. Кроме того, у каждой задачи должен быть какой-то способ обновить свою собственную Операцию текущего выполнения в любом подходящем механизме (обратные вызовы, замыкания, диспетчеризация событий или любой другой механизм, который обеспечивает ваш язык программирования / среда потоков).

Таким образом, пока ваша фактическая работа выполняется в отдельных потоках, соответствующий объект Operation в «главном» потоке постоянно обновляется / уведомляется о прогрессе своего работника. Индикатор выполнения может обновляться соответствующим образом, отображая общее «ожидаемое» время операций в его общее и общее время «выполнения» операций в текущем ходе выполнения, в любом случае, имеет смысл для вашей структуры индикатора выполнения.

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

1 голос
/ 14 февраля 2009

Палка с Observer / Observable для такого рода вещей. Некоторые объекты наблюдают за различными потоками обработки серий и сообщают о состоянии, обновляя сводную панель.

1 голос
/ 14 февраля 2009

Несколько прогресс-баров - не такая уж плохая идея. Или, может быть, сложный индикатор выполнения, который показывает несколько запущенных потоков (например, программы загрузки менеджера иногда). Если пользовательский интерфейс интуитивно понятен, ваши пользователи оценят дополнительные данные.

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

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

...