Udostępnij przez


Wersja linii bazowej: bardzo słaba wydajność aplikacji

Początkowy przykład kodu o niskiej wydajności używany do obliczania aktualizacji jest następujący:

Notatka

Dla uproszczenia w poniższych przykładach nie ma obsługi błędów. Każda aplikacja produkcyjna zawsze sprawdza wartości zwracane.

 

Ostrzeżenie

Pierwsze kilka przykładów aplikacji zapewnia celowo niską wydajność, aby zilustrować ulepszenia wydajności możliwe przy użyciu zmian w kodzie. Nie używaj tych przykładów kodu w aplikacji; są przeznaczone tylko do celów ilustracyjnych.

 

#include <windows.h>

BOOL Map[ROWS][COLS];

void LifeUpdate()
{
    ComputeNext( Map );
    for( int i = 0 ; i < ROWS ; ++i )     //serialized
        for( int j = 0 ; j < COLS ; ++j )
            Set( i, j, Map[i][j] );    //chatty
}

BYTE Set(row, col, bAlive)
{
    SOCKET s = socket(...);
    BYTE byRet = 0;
    setsockopt( s, SO_SNDBUF, &Zero, sizeof(int) );
    bind( s, ... );
    connect( s, ... );
    send( s, &row, 1 );
    send( s, &col, 1 );
    send( s, &bAlive, 1 );
    recv( s, &byRet, 1 );
    closesocket( s );
    return byRet;
}

W tym stanie aplikacja ma najgorszą możliwą wydajność sieci. Problemy z tą wersją przykładowej aplikacji obejmują:

  • Aplikacja jest gadatliwa. Każda transakcja jest za mała — komórki nie muszą być aktualizowane pojedynczo.
  • Transakcje są ściśle serializowane, mimo że komórki mogą być aktualizowane jednocześnie.
  • Bufor wysyłania jest ustawiony na zero, a aplikacja generuje 200-milisekundowe opóźnienie dla każdego wysyłania — trzy razy na komórkę.
  • Aplikacja często się łączy, wykonując połączenie dla każdej komórki. Aplikacje są ograniczone w liczbie połączeń na sekundę dla danego miejsca docelowego ze względu na stan TIME-WAIT, ale nie jest to problem, ponieważ każda transakcja przejmuje ponad 600 milisekund.
  • Aplikacja jest obszerna; wiele transakcji nie ma wpływu na stan serwera, ponieważ wiele komórek pozostaje niezmienionych od aktualizacji do aktualizacji.
  • Aplikacja wykazuje niską jakość przesyłania strumieniowego; niewielkie transfery zużywają dużo CPU i pamięci RAM.
  • Aplikacja przyjmuje reprezentację little-endian dla swoich wysyłania. Jest to naturalne założenie dla bieżącej platformy Windows, ale może być niebezpieczne dla długotrwałego kodu.

Kluczowe metryki wydajności

Następujące metryki wydajności są wyrażane w Czasie Podróży (RTT), przepustowości użytkowej (Goodput) i narzutu protokołu (Protocol Overhead). Aby uzyskać wyjaśnienie tych terminów, zobacz temat Terminologia sieciowa.

  • Czas komórki, czyli czas sieciowy dla pojedynczej aktualizacji komórki, wymaga 4*RTT + 600 milisekund na interakcje Nagle i opóźnionych interakcji ACK.
  • Wartość Goodput jest mniejsza niż 6 bajtów.
  • Obciążenie protokołu wynosi 99,6%.

ulepszanie powolnej aplikacji

Terminologia dotycząca sieci

poprawka 1: Oczyszczenie oczywistych błędów

poprawka 2: Przeprojektowanie w celu zmniejszenia liczby połączeń

poprawka 3: skompresowane wysyłanie bloku

Przyszłe Ulepszenia