Dlaczego paski postępu są tak niedokładne?
Na pierwszy rzut oka wydaje się, że generowanie dokładnej oceny czasu powinno być dość łatwe. W końcu algorytm generujący pasek postępu zna wszystkie zadania, które musi wykonać z wyprzedzeniem ... w prawo?
W większości przypadków prawdą jest, że algorytm źródłowy wie, co należy zrobić z wyprzedzeniem. Jednak ustalenie czasu potrzebnego na wykonanie każdego kroku jest bardzo trudne, jeśli nie praktycznie niemożliwe.
Wszystkie zadania nie są równe
Najprostszym sposobem zaimplementowania paska postępu jest użycie graficznej reprezentacji licznika zadań. Gdzie procent jest po prostu obliczany jako Zakończone zadania / łączna liczba zadań. Chociaż w pierwszym rzędzie ma to sens logiczny, należy pamiętać, że (oczywiście) niektóre zadania wymagają więcej czasu.
Rozważ następujące zadania wykonywane przez instalatora:
- Utwórz strukturę folderów.
- Dekompresuj i kopiuj pliki warte 1 GB.
- Utwórz wpisy rejestru.
- Utwórz wpisy w menu startowym.
W tym przykładzie kroki 1, 3 i 4 zakończyłyby się bardzo szybko, natomiast krok 2 zajęłby trochę czasu. Tak więc pasek postępu pracujący na prostej liczbie szybko przeskoczyłby do 25%, zatrzymał się na chwilę, podczas gdy krok 2 działał, a następnie przeskoczył do 100% niemal natychmiast.
Ten typ implementacji jest dość powszechny wśród pasków postępu, ponieważ, jak wspomniano powyżej, jest łatwy do wdrożenia. Jednak, jak widać, jest on obciążony nieproporcjonalnymi zadaniami rzeczywisty procent postępu w odniesieniu do pozostałego czasu.
Aby obejść ten problem, niektóre paski postępu mogą wykorzystywać implementacje, w których etapy są ważone. Rozważ powyższe kroki, w których względna waga jest przypisana do każdego kroku:
- Utwórz strukturę folderów. [Waga = 1]
- Dekompresuj i kopiuj pliki warte 1 GB. [Waga = 7]
- Utwórz wpisy rejestru. [Waga = 1]
- Utwórz wpisy w menu startowym. [Waga = 1]
Przy użyciu tej metody pasek postępu przesuwałby się o 10% w krokach (jako całkowita waga wynosi 10), a kroki 1, 3 i 4 przesuwały pasek o 10% po zakończeniu, a krok 2 o przesunięcie o 70%. Chociaż z pewnością nie są doskonałe, takie metody są prostym sposobem dodania nieco większej dokładności do procentowego paska postępu.
Dotychczasowe wyniki nie gwarantują przyszłych wyników
Rozważ prosty przykład, w którym prosiłbym cię o policzenie do 50, podczas gdy ja korzystam ze stopera, żeby cię porwać. Powiedzmy, że liczyć do 25 na 10 sekund. Rozsądnie byłoby założyć, że pozostałe liczby zostaną policzone przez dodatkowe 10 sekund, więc śledzenie paska postępu wskazywałoby 50% czasu z 10 sekundami pozostałymi.
Kiedy jednak liczba osiągnie 25, zacznę rzucać na ciebie piłką tenisową. Prawdopodobnie złamie to twój rytm, gdy twoja koncentracja przeniosła się od ścisłego liczenia liczb do uniku kulek rzucanych na twoją drogę. Zakładając, że jesteś w stanie kontynuować liczenie, twoje tempo z pewnością nieco zwolniło. Teraz pasek postępu wciąż się porusza, ale w znacznie wolniejszym tempie, z szacowanym czasem pozostawania w stanie spoczynku lub wspinaniem się w górę.
Aby uzyskać bardziej praktyczny przykład, rozważ pobranie pliku. Aktualnie pobierasz plik o wielkości 100 MB z szybkością 1 MB / s. To bardzo łatwo określić szacowany czas ukończenia. Ale 75% drogi tam, niektóre przeciążenia sieci trafiają, a współczynnik pobierania spada do 500 KB / s.
W zależności od tego, w jaki sposób przeglądarka oblicza pozostały czas, ETA może natychmiast przejść od 25 sekund do 50 sekund (tylko przy użyciu aktualnego stanu: Rozmiar Pozostały / Prędkość pobierania) lub, najprawdopodobniej, przeglądarka używa algorytmu średniej kroczącej, który dostosowałby się do fluktuacji prędkości transferu bez wyświetlania dramatycznych skoków do użytkownika.
Przykład toczącego się algorytmu pobierania pliku może działać w następujący sposób:
- Prędkość transferu z poprzednich 60 sekund jest pamiętana z najnowszą wartością zastępującą najstarszą (np. Wartość 61. zastępuje pierwszą).
- Efektywna szybkość transferu w celu obliczenia jest średnią z tych pomiarów.
- Pozostały czas oblicza się jako: Rozmiar Pozostały / Skuteczna prędkość pobierania
Używając powyższego scenariusza (dla uproszczenia użyjemy 1 MB = 1000 KB):
- Po 75 sekundach pobierania nasze 60 zapamiętanych wartości wynosi 1000 KB. Efektywna szybkość transferu wynosi 1000 KB (60 000 KB / 60), co daje pozostały czas 25 sekund (25 000 KB / 1000 KB).
- W 76 sekund (gdy prędkość transferu spadnie do 500 KB), efektywna prędkość pobierania wynosi ~ 992 KB (59 500 KB / 60), co daje czas pozostały do ~ 24,7 sekund (24 500 KB / 992 KB).
- W 77 sekund: efektywna prędkość = około 983 KB (59,000 KB / 60), pozostały czas około 24.4 sekundy (24 000 KB / 983 KB).
- Po 78 sekundach: efektywna prędkość = 975 KB (58,500 KB / 60), co daje czas pozostały do około 24,1 sekundy (23 500 KB / 975 KB).
Możesz zobaczyć wzorzec pojawiający się tutaj, ponieważ spadek prędkości pobierania powoli włącza się do średniej, która jest używana do oszacowania pozostałego czasu. Zgodnie z tą metodą, jeśli spadek trwał tylko 10 sekund, a następnie powrócił do 1 MB / s, użytkownik prawdopodobnie nie zauważy różnicy (z wyjątkiem bardzo niewielkiego przeciągnięcia w przewidywanym odliczaniu czasu).
Dotarcie do pinezek mosiężnych - jest to po prostu metodologia przekazywania informacji do użytkownika końcowego dla rzeczywistej przyczyny ...
Nie można dokładnie określić, co jest niedeterministyczne
Ostatecznie niedokładność paska postępu sprowadza się do faktu, że próbuje ustalić czas dla czegoś, co jest niedeterministyczne. Ponieważ komputery przetwarzają zadania zarówno na żądanie, jak i w tle, prawie niemożliwe jest ustalenie, jakie zasoby systemowe będą dostępne w dowolnym momencie w przyszłości - a dostępność zasobów systemowych jest potrzebna do wykonania każdego zadania..
Za pomocą innego przykładu załóżmy, że przeprowadzasz aktualizację programu na serwerze, który wykonuje dość intensywną aktualizację bazy danych. Podczas tego procesu aktualizacji użytkownik wysyła wymagające żądanie do innej bazy danych uruchomionej w tym systemie. Teraz zasoby serwera, w szczególności dla bazy danych, muszą przetwarzać żądania zarówno dla aktualizacji, jak i dla zapytania inicjowanego przez użytkownika - scenariusz, który z pewnością będzie szkodliwy dla czasu wykonania. Alternatywnie, użytkownik może zainicjować duże żądanie przesyłania plików, które będzie opodatkowało przepustowość pamięci masowej, co również pogorszyłoby wydajność. Lub zaplanowane zadanie może zostać uruchomione, co powoduje intensywny proces pamięci. Masz pomysł.
Być może bardziej realistyczną instancją dla zwykłego użytkownika - rozważ uruchomienie Windows Update lub skanowanie antywirusowe. Obie te operacje wykonują operacje intensywnie korzystające z zasobów w tle. W rezultacie każdy postęp zależy od tego, co robi użytkownik w danym momencie. Jeśli czytasz e-mail, gdy to działa, najprawdopodobniej zapotrzebowanie na zasoby systemowe będzie niskie, a pasek postępu będzie konsekwentnie poruszać się. Z drugiej strony, jeśli robisz edycję grafiki, twoje zapotrzebowanie na zasoby systemowe będzie znacznie większe, co spowoduje, że pasek postępu będzie schizofreniczny.
Ogólnie rzecz biorąc, po prostu nie ma kryształowej kuli. Nawet sam system nie wie, jaki ładunek będzie znajdował się w jakimkolwiek punkcie w przyszłości.
Ostatecznie to naprawdę nie ma znaczenia
Intencją paska postępu jest, cóż, wskazanie, że rzeczywiście postępy są czynione, a dany proces nie jest zawieszony. Dobrze, gdy wskaźnik postępu jest dokładny, ale zazwyczaj jest to tylko niewielka irytacja, gdy nie jest. W przeważającej części deweloperzy nie poświęcą zbyt wiele czasu i wysiłku na algorytmy paska postępu, ponieważ, szczerze mówiąc, jest o wiele więcej ważnych zadań do spędzenia czasu..
Oczywiście, masz wszelkie prawo do irytacji, gdy pasek postępu przeskoczy do 99% kompletnie od razu, a następnie sprawia, że czekamy 5 minut na pozostały jeden procent. Ale jeśli odpowiedni program działa dobrze, po prostu przypomnij sobie, że programista miał swoje priorytety prosto.