Perché le barre di avanzamento sono così imprecise?
A prima vista, sembra che generare una stima accurata del tempo dovrebbe essere abbastanza facile. Dopo tutto, l'algoritmo che produce la barra di avanzamento conosce tutti i compiti che deve svolgere prima del tempo ... giusto?
Per la maggior parte, è vero che l'algoritmo sorgente sa cosa deve fare prima del tempo. Tuttavia, definire il tempo necessario per eseguire ogni passaggio è un compito molto difficile, se non addirittura impossibile.
Tutte le attività non sono state create uguali
Il modo più semplice per implementare una barra di avanzamento consiste nell'utilizzare una rappresentazione grafica del contatore delle attività. Dove la percentuale completa è semplicemente calcolata come Attività completate / Numero totale di attività. Mentre questo ha un senso logico al primo pensiero, è importante ricordare che (ovviamente) alcune attività richiedono più tempo per essere completate.
Considera le seguenti attività eseguite da un installatore:
- Crea la struttura delle cartelle.
- Decomprimi e copia 1 GB di file.
- Crea voci di registro.
- Crea voci del menu di avvio.
In questo esempio, i passaggi 1, 3 e 4 si completerebbero molto rapidamente mentre il passaggio 2 richiederebbe un po 'di tempo. Quindi una barra di avanzamento che lavora su un conteggio semplice salta al 25% molto rapidamente, si blocca per un po 'mentre il passaggio 2 sta funzionando, e poi salta al 100% quasi immediatamente.
Questo tipo di implementazione è in realtà abbastanza comune tra le barre di avanzamento perché, come detto sopra, è facile da implementare. Tuttavia, come puoi vedere, è soggetto a compiti sproporzionati che distorcono il effettivo percentuale di avanzamento in relazione al tempo rimanente.
Per ovviare a questo problema, alcune barre di avanzamento potrebbero utilizzare implementazioni in cui i passaggi sono ponderati. Considera i passaggi precedenti in cui viene assegnato un peso relativo a ogni passaggio:
- Crea la struttura delle cartelle. [Peso = 1]
- Decomprimi e copia 1 GB di file. [Peso = 7]
- Crea voci di registro. [Peso = 1]
- Crea voci del menu di avvio. [Peso = 1]
Utilizzando questo metodo, la barra di avanzamento si muoverà in incrementi del 10% (come il peso totale è 10) con i passaggi 1, 3 e 4 spostando la barra del 10% al completamento e il passaggio 2 spostandolo del 70%. Sebbene certamente non perfetti, metodi come questo sono un modo semplice per aggiungere un po 'più di precisione alla percentuale della barra di avanzamento.
I risultati passati non garantiscono le prestazioni future
Considera un semplice esempio di me che ti chiede di contare fino a 50 mentre utilizzo un cronometro per cronometrarti. Diciamo che conta fino a 25 in 10 secondi. Sarebbe ragionevole presumere che conti i restanti numeri in altri 10 secondi, quindi una barra di avanzamento che tiene traccia di ciò mostrerà il 50% completo con 10 secondi rimanenti.
Una volta che il tuo conteggio raggiunge i 25, tuttavia, inizio a lanciare palle da tennis contro di te. Probabilmente questo ti spezzerà il ritmo man mano che la tua concentrazione si è spostata dal contare rigorosamente i numeri alle palle schivate lanciate sulla tua strada. Supponendo che tu possa continuare a contare, il tuo ritmo ha certamente rallentato un po '. Così ora la barra di avanzamento è ancora in movimento, ma a un ritmo molto più lento con il tempo stimato rimanente o ad una fermata o in realtà salendo più in alto.
Per un esempio più pratico di questo, si consideri un download di file. Attualmente stai scaricando un file da 100 MB alla velocità di 1 MB / s. Questo è molto facile da determinare il tempo stimato di completamento. Ma il 75% del modo in cui ci sono, alcuni problemi di congestione della rete e la tua velocità di download scende a 500 KB / s.
A seconda di come il browser calcola il tempo rimanente, l'ETA potrebbe passare immediatamente da 25 secondi a 50 secondi (utilizzando solo lo stato attuale: Dimensione Rimanente / Velocità di download) o, molto probabilmente, il browser utilizza un algoritmo di media mobile che si adatta alle fluttuazioni della velocità di trasferimento senza visualizzare salti drammatici per l'utente.
Un esempio di un algoritmo rolling per quanto riguarda il download di un file potrebbe funzionare in questo modo:
- La velocità di trasferimento per i precedenti 60 secondi viene ricordata con il nuovo valore che sostituisce il più vecchio (ad esempio il valore 61st sostituisce il primo).
- La velocità di trasferimento effettiva ai fini del calcolo è la media di queste misurazioni.
- Il tempo rimanente è calcolato come: Dimensione Rimanente / Efficace Velocità di download
Quindi, usando il nostro scenario sopra (per semplicità useremo 1 MB = 1.000 KB):
- A 75 secondi dal download, i nostri 60 valori ricordati sarebbero di 1.000 KB ciascuno. La velocità di trasferimento effettiva è di 1.000 KB (60.000 KB / 60), con un tempo residuo di 25 secondi (25.000 KB / 1.000 KB).
- A 76 secondi (dove la velocità di trasferimento scende a 500 KB), la velocità effettiva di download diventa ~ 992 KB (59.500 KB / 60) che restituisce un tempo rimanente di ~ 24.7 secondi (24.500 KB / 992 KB).
- A 77 secondi: Velocità effettiva = ~ 983 KB (59.000 KB / 60) con tempo rimanente di ~ 24,4 secondi (24000 KB / 983 KB).
- A 78 secondi: Velocità effettiva = 975 KB (58.500 KB / 60) con tempo rimanente di ~ 24,1 secondi (23.500 KB / 975 KB).
È possibile vedere il modello emergente qui come il tuffo nella velocità di download viene lentamente incorporato nella media che viene utilizzata per stimare il tempo rimanente. Con questo metodo, se il dip è durato solo 10 secondi e poi è tornato a 1 MB / s, è improbabile che l'utente noti la differenza (ad eccezione di uno stallo molto piccolo nel conto alla rovescia del tempo stimato).
Raggiungere i chiodini di ottone - questa è semplicemente una metodologia per trasmettere informazioni all'utente finale per la reale causa sottostante ...
Non è possibile determinare con precisione qualcosa che non sia deterministico
In definitiva, l'inesattezza della barra di progresso si riduce al fatto che sta cercando di determinare un momento per qualcosa che non è deterministico. Poiché i computer elaborano le attività sia su richiesta che in background, è quasi impossibile sapere quali risorse di sistema saranno disponibili in qualsiasi momento nel futuro - ed è la disponibilità delle risorse di sistema necessarie per completare qualsiasi attività.
Utilizzando un altro esempio, si supponga di eseguire un aggiornamento del programma su un server che esegue un aggiornamento del database abbastanza intenso. Durante questo processo di aggiornamento, un utente invia una richiesta impegnativa a un altro database in esecuzione su questo sistema. Ora le risorse del server, in particolare per il database, devono elaborare le richieste sia per l'aggiornamento che per la query avviata dall'utente - uno scenario che sarà sicuramente dannoso per i tempi di esecuzione. In alternativa, un utente può avviare una richiesta di trasferimento file di grandi dimensioni che imporrebbe il throughput dello storage, il che andrebbe a detrimento anche delle prestazioni. O potrebbe iniziare un'attività pianificata che esegue un processo ad alta intensità di memoria. Hai un'idea.
Come, forse, un'istanza più realistica per un utente quotidiano: considera l'esecuzione di Windows Update o di una scansione antivirus. Entrambe queste operazioni eseguono operazioni intensive in background. Di conseguenza, i progressi compiuti dipendono da ciò che l'utente sta facendo in quel momento. Se stai leggendo la tua e-mail mentre è in esecuzione, molto probabilmente la richiesta di risorse di sistema sarà bassa e la barra di avanzamento si muoverà in modo coerente. D'altra parte, se stai facendo un editing di grafica, la tua richiesta di risorse di sistema sarà molto più grande e il movimento della barra di avanzamento sarà schizofrenico.
Nel complesso, è semplicemente che non c'è la sfera di cristallo. Nemmeno il sistema stesso sa quale sarà il carico in futuro in qualsiasi momento.
In definitiva, non conta davvero
L'intento della barra di progresso è, beh, indicare che si stanno effettivamente facendo progressi e che il rispettivo processo non è sospeso. È bello quando l'indicatore di avanzamento è preciso, ma in genere è solo un fastidio minore quando non lo è. Per la maggior parte, gli sviluppatori non dedicheranno molto tempo e sforzi agli algoritmi della barra di avanzamento perché, francamente, ci sono compiti molto più importanti da dedicare al tempo.
Naturalmente, hai tutto il diritto di essere infastidito quando una barra di avanzamento salta al 99% completa all'istante e poi ti fa aspettare 5 minuti per il restante 1 percento. Ma se il rispettivo programma funziona bene nel complesso, ricordati che lo sviluppatore aveva le sue priorità dritte.