2010-03-24 41 views
17

La aplicación que estoy escribiendo realiza un algoritmo de longitud que generalmente tarda unos minutos en terminar. Durante este tiempo, me gustaría mostrar al usuario una barra de progreso que indica qué parte del algoritmo se realiza de la forma más precisa posible.Patrones de diseño de barra de progreso?

El algoritmo se divide en varios pasos, cada uno con su propio tiempo típico. Por ejemplo-

  • de inicialización (500 mili-sec)
  • entradas de lectura (5 seg)
  • la etapa 1 (30 seg)
  • paso 2 (3 minutos)
  • salidas de escritura (7 sec)
  • cierre (10 mili-sec)

Cada paso puede reportar su progreso con bastante facilidad mediante el establecimiento de la r Está trabajando en ello, digamos [0 a 150] y luego informa el valor que completó en su bucle principal.

Lo que tengo configurado actualmente es un esquema de monitores de progreso anidados que forman una especie de árbol implícito de informes de progreso.

Todos los monitores de progreso heredan de una interfaz IProgressMonitor:

class IProgressMonitor 
{ 
public: 
    void setRange(int from, int to) = 0; 
    void setValue(int v) = 0; 
}; 

La raíz del árbol es la ProgressMonitor que está conectado a la interfaz GUI real:

class GUIBarProgressMonitor : public IProgressMonitor 
{ 
    GUIBarProgressMonitor(ProgressBarWidget *); 
}; 

cualquier otro nodo en el árbol de son monitores que toman el control de una parte del progreso principal:

class SubProgressMonitor : public IProgressMonitor 
{ 
    SubProgressMonitor(IProgressMonitor *parent, int parentFrom, int parentLength) 
    ... 
}; 

A SubProgressMonitor toma el control del rango [parentFrom, parentFrom+parentLength] de su matriz.

Con este esquema, puedo dividir estáticamente el progreso del nivel superior según la porción relativa esperada de cada paso en el tiempo global. Cada paso puede subdividirse en piezas, etc. '

La principal desventaja de esto es que la división es estática y se hace doloroso hacer cambios de acuerdo con las variables que se descubren en tiempo de ejecución.

Entonces, la pregunta: ¿hay algún patrón de diseño conocido para la supervisión del progreso que resuelva este problema?

Respuesta

1

Este es un problema difícil, hemos luchado con él también en un proyecto anterior.

Lo mejor que se me ocurre es recopilar estadísticas de cuánto tiempo dura cada fase en la vida real, y ajustar las longitudes de intervalo relativas en consecuencia.

No nos hemos puesto en práctica en ese proyecto, aunque (al menos mientras yo estaba allí), así que esto es sólo una idea teórica :-)

4

Pedro fue el enfoque que tomé en un proyecto grande; durante nuestro lanzamiento inicial y piloto, cada uno de nuestros miles de dispositivos móviles enviaron datos de tiempo y uso, y utilizamos las desviaciones promedio, mediana y estándar del tiempo necesario para ajustar la configuración de nuestras tareas (cuando el la tarea se permitió ejecutar, cuánto tiempo se permitió ejecutar, qué valores se usaron en la barra de progreso, etc.). Dado que nuestra solución fue construida como la suya, pero impulsada por los valores proporcionados en un archivo de configuración XML, pensamos en construir esto como un sistema automatizado (por ejemplo, el servidor verificaría estos valores en algún intervalo, notará que ciertas tareas tardaron más tiempo en días de lo que solían y actualizar el archivo de configuración para reprogramarlos o alargarlos), pero pensé que no valía la pena solo para evitar una revisión humana rápida cada pocas semanas.

Como no conozco una solución técnica a su problema, creo que lo que le muestra al usuario (y cuánto tiempo dedica a desarrollar una solución) debería basarse en preocupaciones funcionales: ¿quién está usando esto? ¿Cuán precisa debe ser la información? ¿Es este un proceso interactivo durante el cual no pueden hacer ningún otro trabajo, o pueden dejarlo correr en segundo plano y volver a él? ¿Es el proceso de trabajo durante el cual su función de larga duración ocurre una función sensible al tiempo o de misión crítica?

Lamento que realmente no pueda darle la respuesta que está buscando, pero quizás pensar en lo que está tratando de lograr a grandes rasgos es una buena idea. =)

5

Un enfoque muy interesante es la percepción del usuario.

Chris Harrison publicó un documento sobre cómo usuario percibe el paso del tiempo dependiendo del progreso informado por la barra de progreso (aunque la duración real era obviamente idénticos en todos los experimentos)

Obsérvese que la fórmula de visualización preferido es (x + (1-x)/2) donde x es el progreso real en una escala de 0 a 1 :)

por lo tanto, sugeriría:

  • reúnen algunas estadísticas sobre el porcentaje de tiempo que toma una tarea determinada
  • miden la inicialización y la usan para escalar su progreso en la barra de progreso, siendo pesimistas (prepare un búfer de 10-15% por ejemplo)
  • justo antes de la última tarea (o pocas últimas tareas, siempre que tengan una duración determinística), complete todo para completar la barra de progreso en el tiempo (con aceleración progresiva)

Lo sé, eso no es exacto, pero si los usuarios piensan ¡es más rápido me conformaré con eso!

0

Puede considerar reemplazar la barra de progreso, con un círculo de progreso. Si la tarea tiene N pasos, entonces haga N cuñas en el pie y llene cada cuña como una barra de progreso, a medida que se ejecuta ese paso.

Como paso adicional, quizás se muestre texto para cada paso, por lo que tienen algo que leer mientras avanza el paso.

2

Cree un AggregateProgressMonitor que calcula automáticamente las divisiones de progreso de los niños en función de la información proporcionada por los supervisores de progreso secundarios.El monitor de progreso del niño debe, al menos, informar al padre del tiempo de ejecución "esperado". Los tiempos de ejecución estimados de los monitores secundarios se pueden actualizar luego según sus operaciones respectivas en función de los parámetros de tiempo de ejecución y el informe general de progreso se ajustará en consecuencia y automáticamente.

Algo como esto ...

class IAggregateProgressMonitor : public IProgressMonitor 
{ 
    void setChildValue(IProgressMonitor *, int v); 
    void setChildEstimatedTime(IProgressMonitor *, int v); 
} 

class AggregateProgressMonitor : public IAggregateProgressMonitor 
{ 
    void setChildValue(IProgressMonitor * child, int v) 
    { 
     int aggregateValue = mapChildValueToAggregateValue(child, v); 
     setValue(aggregateValue); 
    } 

    void setChildEstimatedTime(IProgressMonitor * child, ulong ms) 
    { 
     children[child]->estimatedTime = ms; 
     updateChildProgressRatios(); 
    } 
} 

class SubProgressMonitor : public IProgressMonitor 
{ 
    SubProgressMonitor(IAggregateProgressMonitor *parent, int parentFrom, 
        int parentLength) ... ; 
    void setValue(int v) 
    { 
    parent->setChildValue(this, v); 
    } 

    void setEstimatedRunningTime(ulong ms) 
    { 
    parent->setChildEstimatedTime(this, ms); 
    } 
}; 

Usted puede incluso utilizar el tiempo observado del primer paso para volver a asignar los reporteros de situación subsiguientes para ser más exactos.

Deberá mantener un mapa ordenado de algún tipo en el AggregateProgressMonitor para poder rastrear y calcular toda la información de los niños.

Una vez completado, puede extender AggregateProgressMonitor (anulando los métodos de IProgressMonitor) para mostrar el progreso al usuario.