Pomiar prędkości pobierania/wysyłania

0

// Speed
System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
int tempBytes = 0;
sw.Start();

while ((readedBytes = stream.Read(chunk, 0, chunk.Length)) > 0)
{
    str.Write(chunk, 0, readedBytes);
    totalReadedBytes += readedBytes;
    tempBytes += readedBytes;
    if (sw.ElapsedMilliseconds > _upDownUpdateTimeInterval)
    {
        OnChanged(new ProgressChangedEventArgs(totalReadedBytes, size, (int)(((Double)tempBytes / (sw.ElapsedMilliseconds + 1)) * 1000)));
        sw.Reset();
        sw.Start();
        tempBytes = 0;
    }
    if (str.Length == size)
        break;
}
sw.Stop();

To coś służy do pobierania plików (stream = NetworkStream). Problem polega na tym, że już niejednokrotnie miałem zgłaszane, że prędkość po jakimś czasie jest niepoprawna.
To jest pojedyncze pobieranie uruchomione na wątku. Takich wątków jest, np. 20, na każdym chodzi osobny StopWatch, a wszystko jest wrzucane na główny wątek poprzez OnChanged event.

Po przeszukaniu netu znalazłem kilka informacji, między innymi http://kristofverbiest.blogsp[...]8/10/beware-of-stopwatch.html co w jakimś stopniu mogłoby tłumaczyć niepoprawne wyniki w niektórych przypadkach, choć zweryfikować osobiście aktualnie nie mogę. Większość osób informowała, że problem występuje po dłuższym używaniu. Na początku pobiera z normalną prędkością, a potem pokazuje kilkukrotnie niższą, jednak w rzeczywistości pobierając tak samo szybko (zapis pliku na dysku). Natomiast gdy zacząłem szukać innego sposobu na odmierzenie czasu (np. DateTime.UtcNow) to wszędzie było info by używać właśnie StopWatch.

Może to nie wina StopWatch, ale ciężko znaleźć mi inną przyczynę. OnChanged to event podłączony bezpośrednio pod główny wątek, tam dane są jeszcze przeliczane (bajty na KB lub MB) i wyświetlane, ale błąd nie leży w kwestii obliczeń, bo matematyka jest zawsze taka sama tylko w kwestii ich zbierania.
Jak ktoś ma jakieś sugestie, pomysły - będę wdzięczny.

0

, na każdym chodzi osobny StopWatch,

Blee...
Zrób jednego StopWatcha który odpyta wszystkie wątki, zsumuje wartości i raz obliczy.
Nie musisz nawet specjalnie się bawić w thread-safe, sam odczyt pojedynczej wartości jest bezpieczny.

W tej chwili błąd jest prawie na pewno w tym twoim zliczaniu (nie pokazałeś jak sumujesz poszczególne wyniki).

readedBytes
nie ma czegoś takiego jak “readed”.

0

Jednym StopWatch tego nie ogarnę. Każdy chodzi na swoim wątku, ale nie startują w tej samej chwili. Chyba, że chodzi Ci o trochę inne rozwiązanie, które właśnie użyłem, jako zamiennik, tylko, że nie używam StopWatch tylko Timer (System.Timers.Timer). Każdy z takich wątków zapisuje te 3 wartości w 3 polach, a timer co pół sekundy zbiera wszystko i przelicza naraz..

Jeśli chodzi o same wyniki:


e.Time = (int)(((Double)tempBytes / (sw.ElapsedMilliseconds + 1)) * 1000) // Z poprzedniego przykładu
Double speed = e.Time / 1024;
LstView.Set(speed > 1024 ? Math.Round(speed / 1024, 2).ToString() + " MB/s" : speed.ToString() + " KB/s");

Napisałem konkretnie w kwestii StopWatch, chciałem wiedzieć czy to może powodować problemy, bo sam problem rozwiązać mi się uda, ale nie używając StopWatch, czyli tego co najprostsze...

0

Problem polega na tym, że już niejednokrotnie miałem zgłaszane, że prędkość po jakimś czasie jest niepoprawna.

Zastanówmy się, jaka prędkość jest poprawna. W tej chwili liczysz prędkość średnią, od początku ściągania pliku.
Może użytkownicy będą bardziej zadowoleni, gdy zobaczą prędkość chwilową, uśrednioną np. za ostatnie 5 sekund.

Nie podoba mi się też ten StopWatch. Lepiej postęp sprawdzać w ustalonych odstępach czasu, niż odpalać zdarzenie po każdej paczce danych.

0

Zwykle prędkość jest liczona co sekundę, chociaż i co 5 nie byłoby źle.

0

Zastanówmy się, jaka prędkość jest poprawna. W tej chwili liczysz prędkość średnią, od początku ściągania pliku.
Może użytkownicy będą bardziej zadowoleni, gdy zobaczą prędkość chwilową, uśrednioną np. za ostatnie 5 sekund.

Nie za bardzo rozumiem. Prędkość jest liczona co ~0.5 sekundy (+- zapełnienie bufora) w sposób, który widać. Odczytane bajty w ciągu tej 0.5 sekundy są wyliczane z czasem, który upłynął, a całość jest od razu wysyłana i tylko przeliczane są jednostki. Ja nigdzie nie pobieram i nie sumuje całkowitej sumy. "totalReadedBytes" jest używane do obliczenia pobranych danych, ale nie jest wykorzystywany przy liczeniu prędkości.

Nie podoba mi się też ten StopWatch. Lepiej postęp sprawdzać w ustalonych odstępach czasu, niż odpalać zdarzenie po każdej paczce danych.

Uniknąć ciągłego Stop i Reset ? Zapisywać czas w jakiejś zmiennej i tylko odejmować od aktualnej ? Tak też można zrobić, choć to chyba nie jest aż tak istotne.

0

Skoro i tak zliczasz wszystkie pobrane dane to po prostu co sekundę (np w pętli w innym wątku) sprawdzaj ile danych już zostało pobrane i porównuj to z poprzednią wartością. Będziesz wiedział ile danych przybyło w ciągu sekundy i na tej podstawie wyliczysz chwilową prędkość pobierania. Przynajmniej ja bym tak podszedł do tematu.

0

O czym Ty w ogóle mówisz ? Przecież prędkość jest dobrze wyliczana. Tu nie ma żadnej filozofii. Mam liczbę pobranych bajtów w zmiennej "tempBytes" mam czas potrzebny na ich pobranie w StopWatch, więc wyliczam. I nie musi to być pół sekundy czy sekunda, dzielę przez czas który aktualnie będzie w StopWatch. Zresztą, nie bez powodu wrzuciłem kod.

Tak jak mówiłem, pierwszy post to główna pętla pobierania, wszystkie dane są wysyłane eventem do kodu widocznego w drugim poście, a ten trafia już bezpośrednio do usera. Nic więcej pomiędzy tym nie ma.
Jak się gdzieś mylę to mnie poprawcie, a nie tylko kolejne przypuszczenia.

Powyższy kod jest poprawny w działaniu, tylko z jakiegoś powodu, po dłuższym czasie dane wyświetlane po stronie użytkownika są niepoprawne. Wyświetla prędkości w graniach ~50 KB/s, a tak na prawdę pobiera znacznie szybciej - i to jest problem, który staram się rozwiązać, a jedyny element, który może to powodować leży właśnie w tym miejscu.

0
Slynx napisał(a):

Tak jak mówiłem, pierwszy post to główna pętla pobierania, wszystkie dane są wysyłane eventem do kodu widocznego w drugim poście, a ten trafia już bezpośrednio do usera. Nic więcej pomiędzy tym nie ma.

Sam napisałeś, że jest 20 wątków, każdy ma swój stopwatch i wszystkie odpalają OnChanged event - stąd pewnie powyższe wątpliwości. Czyli rozumiem, że wyświetlana jest wartość dla jednego konkretnego wątku.
Moim zdaniem kod jest poprawny (ten, który wkleiłeś; wspomniane 20 wątków jest trochę zagadkowe). W tych linkach, które podałeś, też raczej nie ma źródła problemu - tam jest mowa o błędach przy dużej precyzji pomiaru, a faktyczna prędkość jest, jak rozumiem, dużo większa niż ta zmierzona (poza tym problem wystąpiłby od razu, nie po dłuższym czasie). W jaki sposób użytkownicy sprawdzają, że w rzeczywistości transfer jest szybszy? Patrzą na rozmiar pliku na dysku?

0
Hrypa napisał(a):

W jaki sposób użytkownicy sprawdzają, że w rzeczywistości transfer jest szybszy? Patrzą na rozmiar pliku na dysku?

Dokładnie. Ale powiem Ci, że ja też mam wątpliwości czy aby na pewno wiedzą co zgłaszają. Przeglądałem ten kod, wszystko co odpowiedzialne za pobieranie - nic tam nie ma. Proste działania matematyczne, eventy wysyłające dane bezpośrednio do użytkownika i zwykły odczyt ze strumienia. To zdecydowanie musi być jakiś inny problem -> użytkownicy + serwer, który z jakiegoś powodu ogranicza prędkość, bo innej opcji nie widzę.

Jedyny element jaki podlegał wątpliwości to właśnie ten StopWatch, ale nie ma co na siłę kombinować, ten kod działa poprawnie. A skoro działa poprawnie, to błąd musi leżeć właśnie gdzieś pomiędzy serwerem, a aplikacją, ale w tej kwestii to już raczej sam muszę poszukać rozwiązania. To konkretny serwer pocztowy, więc poszukam w sieci, może ktoś spotkał się podobnym problemem, niekoniecznie korzystając z jakiejś aplikacji.

// -----
Jeszcze Ci dopiszę, bo pytałeś o coś więcej.
20 wątków - 20 wierszy w ListView - każdy ma swój osobny pasek pobierania, szybkość, itp. No.. jeszcze dodatkowo można powiedzieć - "grupowane" jest po 5 wątków (wierszy) i z tego też jest wyliczana prędkość, pasek postępu, itp., ale to akurat mało istotne - to się odbywa gdzie indziej i nie wpływa na pojedyncze wątki. (Mam wrażenie, że trzeba było wkleić schemat, bo to trochę skomplikowane).

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0