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?
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);
}
}
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ą.
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 "
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ć.
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
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