Jak ograniczyć operacje We/Wy in.NET podanie?

Rozwijam aplikację (. NET 4.0, C#), która:
1. Skanuje system plików.
2. Otwiera i odczytuje niektóre pliki.

Aplikacja będzie działać w tle i powinna mieć niewielki wpływ na zużycie dysku. Nie powinno to przeszkadzać użytkownikom, jeśli wykonują swoje zwykłe zadania, a zużycie dysku jest wysokie. I odwrotnie, aplikacja może działać szybciej, jeśli nikt nie korzysta z dysku.
Głównym problemem jest to, że nie znam rzeczywistej ilości i wielkości operacji We / Wy z powodu używania API (mapi32.dll) do odczytu plików. Jeśli Proszę API o zrobienie czegoś Nie wiem ile bajtów czyta aby obsłużyć moją odpowiedź.

Więc pytanie brzmi Jak monitorować i zarządzać użyciem dysku? W tym skanowanie systemu plików i odczyt plików...

Sprawdzić liczniki wydajności, które są używane przez standardowe narzędzie Performance Monitor? Albo w inny sposób?

Author: Preguntón Cojonero Cabrón, 2010-10-25

5 answers

Używając klasy System.Diagnostics.PerformanceCounter, dołącz do licznika PhysicalDisk związanego z indeksowanym dyskiem.

Poniżej znajduje się jakiś kod do zilustrowania, chociaż jego obecnie mocno zakodowany dysk " C:". Będziesz chciał zmienić" C: "na dysk, który skanuje twój proces. (Jest to przybliżony przykładowy kod tylko w celu zilustrowania istnienia liczników wydajności - nie traktuj go jako dostarczającego dokładnych informacji-powinien być zawsze używany tylko jako przewodnik. Zmiana na własną cel)

Obserwuj licznik% czasu bezczynności , który wskazuje, jak często napęd robi cokolwiek. 0% idle oznacza, że dysk jest zajęty, ale niekoniecznie oznacza, że jest płaski i nie może przesłać większej ilości danych.

Połącz % czas bezczynności z bieżącą długością kolejki dysków , a to powie Ci, czy dysk jest tak zajęty , że nie może obsłużyć wszystkich żądań danych. Jako ogólne wytyczne, wszystko powyżej 0 oznacza napęd jest prawdopodobnie płasko-out zajęty i wszystko powyżej 2 oznacza, że napęd jest całkowicie nasycony. Zasady te dotyczą zarówno dysków SSD, jak i HDD dość dobrze.

Każda wartość, którą odczytujesz, jest wartością chwilową w danym momencie. Powinieneś zrobić średnią bieżącą dla kilku wyników, np. wykonać odczyt co 100ms i średnio 5 odczytów przed użyciem informacji z wyniku do podjęcia decyzji (tzn. czekać, aż liczniki się rozliczą przed złożeniem następnego żądania IO).

internal DiskUsageMonitor(string driveName)
{

    // Get a list of the counters and look for "C:"

    var perfCategory = new PerformanceCounterCategory("PhysicalDisk");
    string[] instanceNames = perfCategory.GetInstanceNames();

    foreach (string name in instanceNames)
    {
        if (name.IndexOf("C:") > 0)
        {
            if (string.IsNullOrEmpty(driveName))
               driveName = name;
        }
    }


    _readBytesCounter = new PerformanceCounter("PhysicalDisk", 
                                               "Disk Read Bytes/sec", 
                                               driveName);

    _writeBytesCounter = new PerformanceCounter("PhysicalDisk", 
                                                "Disk Write Bytes/sec", 
                                                driveName);

    _diskQueueCounter = new PerformanceCounter("PhysicalDisk", 
                                               "Current Disk Queue Length", 
                                               driveName);

    _idleCounter = new PerformanceCounter("PhysicalDisk",
                                          "% Idle Time", 
                                          driveName);
    InitTimer();
}

internal event DiskUsageResultHander DiskUsageResult;

private void InitTimer()
{
    StopTimer();
    _perfTimer = new Timer(_updateResolutionMillisecs);
    _perfTimer.Elapsed += PerfTimerElapsed;
    _perfTimer.Start();
}

private void PerfTimerElapsed(object sender, ElapsedEventArgs e)
{
    float diskReads = _readBytesCounter.NextValue();
    float diskWrites = _writeBytesCounter.NextValue();
    float diskQueue = _diskQueueCounter.NextValue();
    float idlePercent = _idleCounter.NextValue();

    if (idlePercent > 100)
    {
        idlePercent = 100;
    }

    if (DiskUsageResult != null)
    {
        var stats = new DiskUsageStats
                        {
                                DriveName = _readBytesCounter.InstanceName,
                                DiskQueueLength = (int)diskQueue,
                                ReadBytesPerSec = (int)diskReads,
                                WriteBytesPerSec = (int)diskWrites,
                                DiskUsagePercent = 100 - (int)idlePercent
                        };
        DiskUsageResult(stats);
    }
}
 19
Author: Neil Fenwick,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-02 13:59:11

Coś do przemyślenia: co jeśli istnieją inne procesy, które stosują tę samą (lub podobną) strategię? Który z nich będzie działał podczas "bezczynności"? Czy inne procesy mają szansę w ogóle wykorzystać czas bezczynności?

Oczywiście nie można tego zrobić poprawnie, chyba że istnieje jakiś dobrze znany mechanizm systemu operacyjnego do sprawiedliwego podziału zasobów w czasie bezczynności. W systemie windows odbywa się to poprzez wywołanie SetPriorityClass.

Ten dokument o priorytetyzacji We/Wy w Vista wydaje się sugerować, że IDLE_PRIORITY_CLASS tak naprawdę nie obniży priorytetu żądań wejścia / Wyjścia (chociaż zmniejszy priorytet szeregowania dla procesu). Vista dodała do tego nowe wartości PROCESS_MODE_BACKGROUND_BEGIN i PROCESS_MODE_BACKGROUND_END.

W C# można normalnie ustawić priorytet procesu za pomocą .PriorityClass property. Nowe wartości dla Vista nie są jednak dostępne, więc będziesz musiał wywołać funkcję Windows API bezpośrednio. Możesz to zrobić tak:

[DllImport("kernel32.dll", CharSet=CharSet.Auto, SetLastError=true)]
public static extern bool SetPriorityClass(IntPtr handle, uint priorityClass);

const uint PROCESS_MODE_BACKGROUND_BEGIN = 0x00100000;

static void SetBackgroundMode()
{
   if (!SetPriorityClass(new IntPtr(-1), PROCESS_MODE_BACKGROUND_BEGIN))
   {
      // handle error...
   }
}

Nie testowałem powyższego kodu. Nie zapominaj, że może działać tylko na Vista lub lepiej. Będziesz musiał użyć Environment.OSVersion, aby sprawdzić wcześniejsze systemy operacyjne i wdrożyć strategię awaryjną.

 3
Author: Wim Coenen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-07 14:55:01

Dawno temu Microsoft Research opublikował artykuł na ten temat (niestety nie pamiętam adresu url).
Z tego co pamiętam:

  • program zaczął wykonywać bardzo niewiele "elementów roboczych".
  • Mierzono, ile czasu zajmuje im każdy "przedmiot pracy".
  • Po uruchomieniu przez chwilę, mogli sprawdzić, jak szybko" element roboczy " był bez obciążenia systemu.
  • od tej pory, jeśli "element roboczy" był szybki (np. żaden inny programista nie wysuwał żądań), robili więcej wnioski, w przeciwnym razie wycofane

Podstawowy ideał to:

"Jeśli mnie spowalniają, to ja musi je spowalniać, więc mniej praca, jeśli jestem spowolniony "

 2
Author: Ian Ringrose,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-10-25 12:26:02

Zobacz to pytanie i to również dla powiązanych zapytań. Sugerowałbym proste rozwiązanie, po prostu pytając o bieżące użycie dysku i procesora % co tak często, i tylko kontynuować bieżące zadanie, gdy są one poniżej określonego progu. Po prostu upewnij się, że Twoja praca jest łatwo podzielona na zadania, a każde zadanie można łatwo i skutecznie rozpocząć/zatrzymać.

 1
Author: mike,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:31:14

Sprawdź, czy wygaszacz jest uruchomiony ? Dobre wskazanie, że użytkownik jest z dala od klawiatury

 0
Author: Fredrik Leijon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-10-25 10:53:08