Come calcolare i progressi complessivi in fasi indipendenti?

2

Quando si utilizza una richiamata per mostrare lo stato di avanzamento in un'attività multifase, non so come calcolare il progresso per fase. Una delle fasi è la raccolta di dati, che differiscono di dimensioni da esecuzione a esecuzione.

  • L'inserimento di percentuali globali nelle chiamate su tutto il codice richiede modifiche non appena viene aggiunta / rimossa una fase e non funziona correttamente con la modifica della dimensione dei dati.

  • L'uso di un incremento fisso per fase non aiuta neanche, poiché la somma potrebbe essere inferiore o superiore al 100% - oppure si interrompe di nuovo con gli incrementi su tutto il codice.

  • Ho persino iniziato a pensare di registrare il tempo impiegato e di usare questi numeri per fare stime dinamiche durante la prossima esecuzione - ma questo è eccessivo, credo.

Ci sono buoni modi per determinare il progresso per fase, in qualche modo automaticamente?

Esistono schemi di progettazione per evitare di inserire numeri fissi nel codice?

    
posta virtualnobi 25.11.2018 - 22:05
fonte

3 risposte

1

Una soluzione semplice qui se applicabile (non consolida il progresso per le operazioni asincrone che funzionano indipendentemente l'una dall'altra, sebbene tu possa ancora usare questo metodo per quelli per calcolare percentuali al loro interno) e puoi anticipare il numero di fasi in anticipo in un contesto esterno (anche se non è possibile prevedere quanto lavoro è richiesto in ogni fase prima di invocarli), il che porta a una barra di progresso * abbastanza liscia * è la seguente:

  • It might not increment in progress in a perfectly consistent way across phases, but should still keep moving forward without going past 100%.

Pseudocodice:

funcprogress(n):ifstack_size<n:return(steps[n]/total[n])+(1/total[n])*progress(n+1);else:return0;

Speriamocheloschemaeilcodicetidianogiàun'ideadell'implementazioneusandoun"stack di progresso" e qualche semplice aritmetica per calcolare il progresso fino ad ora, e puoi annidarli quanto vuoi (fasi che si dividono in sotto -le fasi che si suddividono in fasi sub-sub) senza preoccuparsi di traboccare la barra e superare il 100% o qualcosa del genere.

Tutto ciò che devi fare è in un contesto esterno, anticipare quante fasi hai (3 in questo caso), nel qual caso incrementerai il progresso con incrementi del 33,3% per fase. Ma quando chiamiamo la funzione per phase 1 , potremmo scoprire che questa prima fase richiede 100 sottomulti da completare dopo aver chiamato la funzione, a quel punto il 33,3% di progresso, per parlare, poi viene incrementato di 100 passi per anticipo dallo 0% al 33% e così via. Il codice client potrebbe assumere questa forma:

function some_outer_operation(progress)
{
    // begin performing a total of 3 units/steps of work
    progress.begin(3)
    phase1()
    progress.step()

    phase2()
    progress.step()

    phase3()
    progress.step()
}

function phase1()
{
     // begin performing a total of 100 units/steps of work
     progress.begin(100)
     for j in range(1, 100):
     {
         some_work()
         progress.step()
     }
}

... qualcosa di questo tipo e chiamate ricorsive a begin "suddividono" il pezzo esterno del progresso da incrementare. Quando il numero di passaggi raggiunge il totale per una fase o sottofase o sottofase secondaria o qualsiasi altra cosa, puoi uscire dalla pila. Ciò richiede comunque la specificazione dei numeri ma non richiede necessariamente di avere così tante informazioni in anticipo su tutti i passaggi coinvolti in tutte queste chiamate di funzioni annidate, solo il numero di fasi / fasi che coinvolgono in una particolare funzione e non le "sotto-funzioni" ".

Stranamente semplice come questa soluzione, lo faccio notare perché ho visto soluzioni "piatte" molto contorte (senza questo tipo di stack per operazioni annidate) in cui gli sviluppatori dovevano anticipare il numero totale di passaggi per tutto in anticipo e che a volte richiede il controllo a raggi x dell'implementazione delle funzioni chiamate e dei richiami di funzione delle funzioni chiamate e così via. In questo modo si evita che una grande quantità di conoscenze sia richiesta in anticipo e richiede solo che una funzione abbia bisogno di sapere quanti passaggi si esegue, non tutte le funzioni più in profondità nello stack di chiamate.

Ovviamente potrebbe non essere perfettamente coerente nel modo in cui aumenta (es .: potrebbe richiedere 1 secondo per passare dallo 0 al 33% e 3 secondi per passare dal 33% al 66%), ma può rimanere molto fluido e reattivo e in continua evoluzione in corso, a patto che i passaggi siano abbastanza dettagliati nei tuoi "leaf" call (la tua fase o sottofase o sub-sub-sub-sub-fase o quant'altro).

I even started thinking about recording the time taken, and using these numbers to make dynamic estimations during the next run - but that's overkill, I think.

Se si arriva a questo, vorrei solo dare il consiglio di mostrare solo qualcosa in corso senza una barra di avanzamento, di per sé. Si sta facendo così di fantasia per così poco in cambio se non è possibile anticipare nemmeno il numero di fasi coinvolte in anticipo (es: un euristico che richiede N passa sopra i dati dove N non può essere anticipato in anticipo prima dell'algoritmo in corso di completamento).

Le barre di avanzamento spesse che non aumentano molto agevolmente, inoltre, non si sentono così male se ti piace qualcosa di animazione accanto e puoi annullare l'operazione all'istante, ad esempio. Comunica abbastanza che l'applicazione non si è appena arrestata e non ha più risposto. Quindi non dovresti nemmeno preoccuparti di "suddividere" la barra di avanzamento per i sottomulti delle fasi e solo invece assicurarti che l'interfaccia utente continui ad aggiornarsi e mostri qualcosa che va avanti ad un frame rate ragionevole e risponde abbastanza velocemente se l'utente può abortire anche se la barra non si muove a un ritmo così regolare e rapido.

    
risposta data 03.12.2018 - 19:14
fonte
6

I computer sono esplosivi. Le previsioni su hard coding sono sciocche.

Dato che ritieni che le prestazioni di registrazione siano eccessive, la cosa migliore che puoi fare è scaricare quell'attività all'utente. Mostra chiaramente in quale fase ti trovi. Puoi mostrare un tempo trascorso per aiutare l'utente ad abituarsi a quanto tempo impiega questo sistema.

Se le tue fasi hanno un numero calcolabile di iterazioni, puoi mostrare dove si trovano. Ma questo sarà ingannevole se il lavoro svolto dopo l'iterazione è significativo.

La maggior parte degli utenti è felice se sembra che il computer stia facendo qualcosa. Dimostra a loro che il computer non è bloccato e che aspetteranno mentre lavori.

    
risposta data 26.11.2018 - 03:49
fonte
3

Il modo usuale per fare ciò è determinare quante unità di lavoro si verificheranno, quindi fare in modo che l'API restituisca il numero completato o la percentuale completa del totale. Per qualcosa come un gestore di download, il numero di unità di lavoro sarebbe la somma del numero di byte di tutti i file selezionati per il download, ad esempio, o forse solo il numero totale di file da scaricare. (Entrambe sono cose ragionevoli da usare per unità di lavoro, ma con solo il numero di file, un file potrebbe essere 100 byte e un altro 100GB, il che significa che gli utenti della tua API non otterranno le migliori informazioni dalla tua API in quel caso .)

Nel tuo caso, hai la possibilità di dividerlo in fasi (sembra che ci sia una fase di raccolta e una fase di elaborazione, almeno, forse di più?), dove ogni fase è una unità di lavoro. Hai un modo per dire quante cose saranno raccolte nella fase di raccolta? In tal caso, è possibile sommare il numero di elementi da raccogliere e sapere quante unità di lavoro vengono eseguite durante la fase di raccolta. (Allo stesso modo, ognuno di questi ha bisogno di essere elaborato presumibilmente, quindi sai quante unità di lavoro nella fase di elaborazione, ecc.) In caso contrario, devi lasciare la fase come un'unità intera o utilizzare un indicatore di progresso indeterminato di qualche tipo.

Una cosa che eviterei di fare è aggiungere più unità di lavoro dopo che hai già detto a un cliente quante unità di lavoro ci saranno. È molto confuso per gli utenti (e senza dubbio gli sviluppatori che usano la tua API) quando una barra di avanzamento regredisce col passare del tempo invece di progredire monotonicamente.

    
risposta data 25.11.2018 - 23:17
fonte

Leggi altre domande sui tag