Varför är framstegsstänger så felaktiga?
Vid första tanken verkar det som att generera en noggrann uppskattning av tiden borde vara ganska lätt. Trots allt vet algoritmen som producerar framdriftsfältet alla de uppgifter som den behöver göra före tid ... rätt?
För det mesta är det sant att källalgoritmen vet vad den behöver göra före tid. Att klämma fast den tid det tar att utföra varje steg är dock en mycket svår, om inte praktiskt taget omöjlig uppgift.
Alla uppgifter är inte skapade lika
Det enklaste sättet att implementera en progressiv bar är att använda en grafisk representation av uppgiftsräknaren. Där procenten fullständigt beräknas enkelt som Avslutade uppgifter / Totalt antal uppgifter. Även om detta ger en logisk förståelse på första tanke, är det viktigt att komma ihåg att (uppenbarligen) vissa uppgifter tar längre tid att slutföra.
Tänk på följande uppgifter utförda av en installatör:
- Skapa mappstruktur.
- Dekomprimera och kopiera 1 GB värde av filer.
- Skapa registerposter.
- Skapa startmeny poster.
I det här exemplet skulle steg 1, 3 och 4 slutföra mycket snabbt medan steg 2 skulle ta lite tid. Så en framstegsbar som arbetar med en enkel räkning skulle hoppa till 25% väldigt snabbt, stanna en stund medan steg 2 arbetar och sedan hoppa till 100% nästan omedelbart.
Denna typ av implementering är faktiskt ganska vanlig bland framstegsfält, eftersom det som sagt ovan är lätt att implementera. Men som du kan se är det föremål för oproportionerliga uppgifter som vinklar faktisk Progressprocentandel när det gäller återstående tid.
För att arbeta runt om det här kan vissa framstegsfält använda implementeringar där steg viktas. Tänk på stegen ovan där en relativ vikt tilldelas varje steg:
- Skapa mappstruktur. [Vikt = 1]
- Dekomprimera och kopiera 1 GB värde av filer. [Vikt = 7]
- Skapa registerposter. [Vikt = 1]
- Skapa startmeny poster. [Vikt = 1]
Med hjälp av den här metoden går framdriftsfältet i steg om 10% (eftersom den totala vikten är 10) med steg 1, 3 och 4 flyttar baren 10% vid fullbordandet och steg 2 flyttar det 70%. Medan det inte är helt perfekt, är metoder som detta ett enkelt sätt att lägga till lite mer noggrannhet i progressfältet.
Tidigare resultat garanterar inte framtida resultat
Tänk på ett enkelt exempel på att jag ber dig räkna till 50 medan jag använder en stoppur för att klara dig. Låt oss säga att du räknar till 25 på 10 sekunder. Det vore rimligt att anta att du kommer att räkna de återstående numren på ytterligare 10 sekunder, så en spårning av progressfältet skulle visa 50% komplett med 10 sekunder kvar.
När din räkning når 25, börjar jag kasta tennisbollar på dig. Detta kommer sannolikt att bryta din rytm eftersom din koncentration har flyttat från strängt räkna nummer till att dodging bollar kastade dig. Om du antar att du kan fortsätta räkna, har din takt definitivt minskat lite. Så nu går framdriftsfältet fortfarande, men i en mycket långsammare takt med den beräknade tiden som återstår antingen vid stillestånd eller faktiskt klättring högre.
För ett mer praktiskt exempel på detta, överväg en filhämtning. Du hämtar för närvarande en 100 MB-fil med en hastighet på 1 MB / s. Det här är väldigt enkelt att bestämma beräknad slutförd tid. Men 75% av vägen där, en del trafikstockningar träffar och din nedladdningshastighet sjunker till 500 KB / s.
Beroende på hur webbläsaren beräknar den återstående tiden kan din ETA direkt gå från 25 sekunder till 50 sekunder (endast med nuvarande tillstånd: Återstående storlek / Hastighet) eller mest sannolikt använder webbläsaren en rullande medelalgoritm som skulle anpassa sig för fluktuationer i överföringshastighet utan att visa dramatiska hopp för användaren.
Ett exempel på en rullande algoritm när det gäller att hämta en fil kan fungera så här:
- Överföringshastigheten för de föregående 60 sekunderna kommer ihågs med det nyaste värdet som ersätter det äldsta (t ex 61: e värdet ersätter det första).
- Den effektiva överföringshastigheten för beräkningens syfte är medelvärdet av dessa mätningar.
- Återstående tid beräknas som: Storlek kvarvarande / Effektiv nedladdningshastighet
Så använder vi vårt scenario ovan (för enkelhets skull använder vi 1 MB = 1.000 KB):
- Vid 75 sekunder i hämtningen kommer våra 60 minnesvärden att vara 1,000 KB. Den effektiva överföringshastigheten är 1000 kB (60 000 kB / 60) vilket ger en återstående tid på 25 sekunder (25 000 kB / 1000 kB).
- Vid 76 sekunder (där överföringshastigheten sjunker till 500 kB) blir den effektiva nedladdningshastigheten ~ 992 KB (59 500 kB / 60), vilket ger en återstående tid på ~ 24,7 sekunder (24 500 kB / 992 kB).
- Vid 77 sekunder: Effektiv hastighet = ~ 983 KB (59 000 kB / 60) vilket ger resterande tid på ~ 24,4 sekunder (24 000 kB / 983 kB).
- Vid 78 sekunder: Effektiv hastighet = 975 KB (58 500 kB / 60) vilket ger resterande tid på ~ 24,1 sekunder (23 500 kB / 975 kB).
Du kan se mönstret som kommer fram här, eftersom dip i nedladdningshastigheten sakta införlivas i medelvärdet som används för att uppskatta den återstående tiden. Under den här metoden är det osannolikt att användaren inte kommer att märka skillnaden (spara för en mycket liten stall i beräknad tidräkning) om dipet bara varade i 10 sekunder och sedan återvände till 1 MB / s..
Komma till brass tacks - det här är helt enkelt metodiken för att vidarebefordra information till slutanvändaren för den faktiska underliggande orsaken ...
Du kan inte noggrant bestämma något som är Nondeterministic
I slutändan beror progressionsfelaktigheten på det faktum att det försöker bestämma en tid för något som är nondeterministic. Eftersom datorer behandlar uppgifter både efterfrågan och i bakgrunden är det nästan omöjligt att veta vilka systemresurser som kommer att finnas tillgängliga när som helst i framtiden - och det är tillgången på systemresurser som behövs för att någon uppgift ska kunna slutföras.
Använd ett annat exempel, anta att du kör en programuppgradering på en server som utför en ganska intensiv databasuppdatering. Under denna uppdateringsprocess skickar en användare en krävande begäran till en annan databas som körs på det här systemet. Nu måste serverresurserna, specifikt för databasen, behandla förfrågningar både för din uppgradering och för användarens initierade fråga - ett scenario som säkert kommer att vara ömsesidigt skadligt för exekveringstiden. Alternativt kan en användare initiera en stor filöverföringsförfrågan som skulle skatta lagringskapaciteten vilket skulle också skada prestandan. Eller en schemalagd uppgift kan sparka ut som utför en minnesintensiv process. Du får idén.
Som kanske en mer realistisk instans för en daglig användare - överväga att köra Windows Update eller en virusskanning. Båda dessa operationer utför resursintensiva operationer i bakgrunden. Till följd av detta är framstegen varje tillverkning beroende av vad användaren gör vid den tiden. Om du läser ditt e-postmeddelande medan detta körs, är det troligt att efterfrågan på systemresurser kommer att vara låg och framdriftsfältet kommer att flytta konsekvent. Å andra sidan, om du gör grafikredigering så kommer din efterfrågan på systemresurser att bli mycket större vilket kommer att orsaka att progressionsfältet rör sig för att vara schizofrena.
Sammantaget är det helt enkelt att det inte finns någon kristallkula. Inte ens systemet själv vet vilken belastning det kommer att vara under någon gång i framtiden.
I slutändan betyder det verkligen inte
Syftet med framdriftsfältet är att väl ange att framsteg verkligen görs och att respektive process inte hängs. Det är trevligt när framdriftsindikatorn är korrekt, men vanligtvis är det bara en mindre irritation när det inte är det. För det mesta kommer utvecklare inte att ägna mycket tid och ansträngning till framstegsalgoritmer eftersom det är uppriktigt att det finns mycket viktigare uppgifter att spendera tid på.
Självklart har du all rätt att vara irriterad när en framdriftslinje hoppar till 99% färdig direkt och sedan får du vänta 5 minuter för resterande 1 procent. Men om respektive program fungerar bra övergripande, bara påminna dig om att utvecklaren hade sina prioriteringar raka.