Dlaczego musimy czekać na We / Wy?

28

Zawsze wiadomo, że operacje na dyskach są powolne i znamy powody ich powolności. Pytanie brzmi więc, dlaczego musimy czekać na We / Wy lub dlaczego istnieje coś takiego jak IOWait itp.?

Mam na myśli, że zauważyłem, że kiedy wykonujesz jakieś zadania we / wy w tle, twój komputer zasadniczo działa znacznie wolniej, szczególnie zauważyłem, że kiedy używasz Linuksa, jeśli wykonujesz dłuższe zadania we / wy , system operacyjny staje się prawie bezużyteczny, dopóki nie zostanie ukończony.

Rzeczywiście znalazłem ten temat w artykule, jest też fragment:

Oczekiwanie we / wy wynosi 12,1%. Ten serwer ma 8 rdzeni (przez cat / proc / cpuinfo). Jest to bardzo blisko (1/8 rdzeni = 0,125)

Zasadniczo oznacza to, że spowalnia dużo komputer, dlaczego? Mam na myśli OK, teraz normalny komputer ma co najmniej 2 rdzenie, czasem 4 lub czasami mają więcej z powodu hiperwątkowania lub coś w tym rodzaju. Ale teraz pytanie brzmi: dlaczego procesor tak naprawdę musi tam pozostać, praktycznie nie robiąc nic poza czekaniem na IO? Mam na myśli podstawową ideę lub architekturę zarządzania procesem, teraz nie wiem, czy to system operacyjny jest za to odpowiedzialny, czy sprowadza się do części sprzętowej, ale procesor powinien mieć możliwość oczekiwania lub sprawdzaj regularnie, jednocześnie wykonując wiele innych zadań i wracając do procesu IO, gdy będzie gotowy. Rzeczywiście, jeśli to takie trudne zadanie, a procesor musiałby poczekać, dlaczego nie czy to jest bardziej wydajnie zarządzane przez sprzęt? Na przykład może istnieć rodzaj mini procesora, który po prostu na niego poczeka i dostarczy niewielką część danych do rzeczywistej jednostki centralnej, gdy tylko wróci do procesu, a więc proces zostanie powtórzony i nie mielibyśmy praktycznie poświęcić cały rdzeń procesora procesowi kopiowania danych ... A może to ja wymyślę tego rodzaju rzeczy i dostanę za to nagrodę Nobla? : S

Teraz w porządku, naprawdę kładę to teraz z perspektywy obserwatorów i tak naprawdę nie zagłębiłem się w ten temat, ale naprawdę nie rozumiem, dlaczego procesor musi pracować z prędkością HDD, podczas gdy może po prostu zrób coś innego i wróć na HDD, gdy będzie gotowy. Chodzi o to, aby nie przyspieszyć aplikacji, która potrzebuje operacji IO lub procesu kopiowania itp., Ale chodzi o to, aby minimalnie wpływać na zużycie procesora podczas wykonywania tej operacji, aby system operacyjny mógł wykorzystać ją do innych procesów i użytkownika nie musiałbym odczuwać ogólnego opóźnienia komputera podczas wykonywania operacji kopiowania ...

Arturas M.
źródło
41
„podczas gdy może po prostu zrobić coś innego” - na przykład? Musi pracować z danymi. Jeśli tych danych nie ma w pamięci podręcznej L1 procesora, należy je pobrać z pamięci podręcznej L2. Jeśli nie znajduje się w pamięci podręcznej L2, musi pobrać z L3 (jeśli ma). Jeśli nie ma go wcale w pamięci podręcznej, musi uzyskać dostęp do pamięci głównej. Jeśli nie jest w głównej pamięci ... musi uzyskać dostęp do dysku twardego.
Oded
39
Komputer robi coś innego; jądro blokuje wątek, dopóki operacja IO nie zostanie zakończona, umożliwiając uruchomienie innych wątków / procesów. Ale jeśli wszystko czeka na dysku we / wy, nie ma nic innego do roboty.
Pułkownik Trzydzieści Dwa
6
Musisz poczekać, aż programy dotrą do wieży we / wy i wysłać ci swoje frisbee!
Almo
1
@immibis Prawidłowo! :)
Almo
2
Zazwyczaj współczesne systemy operacyjne robią to, na co narzekasz, że tego nie robią - operacje IO są wysyłane na odpowiedni sprzęt, a sprzęt generuje przerwania, co oznacza, że ​​operacje zostały wykonane. Procesy oczekujące na IO są zwykle blokowane podczas oczekiwania (można to zmienić). Jeśli wiele procesów czeka na We / Wy i żadne inne procesy nie mają nic do zrobienia dla CPU, nie ma wiele do zrobienia. Możesz także skończyć w piekle z zamianą memów. Pisanie programów efektywnie wykorzystujących procesor, pamięć i operacje wejścia / wyjścia wymaga specjalnych umiejętności, a to, co działa, wpływa również na to, co działa najlepiej.
nategoose

Odpowiedzi:

19

Opisane schematy We / Wy są obecnie używane na komputerach.

dlaczego procesor tak naprawdę musi tam pozostać, praktycznie nie robiąc nic poza czekaniem na IO?

Jest to najprostsza możliwa metoda we / wy: zaprogramowane we / wy . Wiele systemów wbudowanych i mikroprocesorów niskich / niskich posiada tylko jedną instrukcję wejściową i jedną instrukcję wyjściową. Procesor musi wykonać jawną sekwencję instrukcji dla każdego odczytanego lub zapisanego znaku.

ale procesor powinien mieć możliwość regularnego czekania lub sprawdzania, jednocześnie wykonując wiele innych zadań i wracając do procesu IO, gdy jest gotowy

Wiele komputerów osobistych ma inne schematy We / Wy. Zamiast czekać w ciasnej pętli, aż urządzenie będzie gotowe ( zajęte oczekiwanie ), procesor uruchamia urządzenie we / wy, prosząc go o wygenerowanie przerwania po zakończeniu ( we / wy sterowane przerwaniem ).

Chociaż operacje wejścia / wyjścia sterowane przerwaniami są krokiem naprzód (w porównaniu do zaprogramowanych operacji we / wy), wymagają one przerwania dla każdej przesyłanej postaci i są drogie ...

Na przykład może istnieć rodzaj mini procesora, który po prostu na niego poczeka i dostarczy niewielką część danych do rzeczywistej jednostki centralnej, gdy tylko wróci do procesu, a więc proces zostanie powtórzony i nie mielibyśmy praktycznie poświęcić cały rdzeń procesora procesowi kopiowania danych ...

Rozwiązaniem wielu problemów jest zlecenie wykonania pracy komuś innemu! :-)

Kontroler / układ DMA (bezpośredni dostęp do pamięci) pozwala na zaprogramowane wejścia / wyjścia, ale może to zrobić ktoś inny!

W przypadku DMA procesor musi jedynie zainicjować kilka rejestrów i może robić coś innego, dopóki transfer nie zostanie zakończony (a przerwanie zostanie podniesione).

Nawet DMA nie jest całkowicie darmowy: urządzenia o dużej prędkości mogą wykorzystywać wiele cykli magistrali dla odniesień do pamięci i odniesień do urządzeń ( kradzież cykli ), a procesor musi czekać (układ DMA zawsze ma wyższy priorytet magistrali).

Oczekiwanie we / wy wynosi 12,1%. Ten serwer ma 8 rdzeni (przez cat / proc / cpuinfo). Jest to bardzo blisko (1/8 rdzeni = 0,125)

Myślę, że pochodzi to od: Zrozumienie We / Wy dysku - kiedy powinieneś się martwić?

Cóż, to nie jest dziwne: system (mySQL) musi pobrać wszystkie wiersze przed manipulowaniem danymi i nie ma innych działań.

Tutaj nie ma problemu z architekturą komputera / systemem operacyjnym. Tak właśnie jest ustawiony przykład.

Co najwyżej może to być problem ze strojeniem RDBMS lub problem z zapytaniem SQL (brak indeksu, zły plan zapytań, złe zapytanie ...)

manlio
źródło
24

Możliwe jest zapisanie asynchronicznego We / Wy, w którym powiesz systemowi operacyjnemu, aby wysłał dysk do odczytu / zapisu, a następnie zrób coś innego, a następnie sprawdzi, czy jest zrobiony. Jest daleki od nowego. Starsza metoda używa innego wątku dla IO.

Wymaga to jednak, abyś miał coś do zrobienia podczas wykonywania tego odczytu i nie będziesz mógł dotykać bufora, który przekazałeś dla wyniku.

Znacznie łatwiej jest również zaprogramować, gdy założymy, że wszystko blokuje IO.

Gdy wywołasz funkcję blokowania odczytu, wiesz, że nie powróci, dopóki coś nie zostanie odczytane i natychmiast po tym, jak będziesz mógł rozpocząć przetwarzanie na nim.

Typowa pętla odczytu jest dobrym przykładem

//variables that the loop uses
char[1024] buffer;
while((read = fread(buffer, 1024, 1, file))>0){
    //use buffer
}

W przeciwnym razie należy zapisać bieżący stan funkcji (zwykle w postaci wywołania zwrotnego + wskaźnik userData) i przekazać go + identyfikator operacji odczytu z powrotem do select()pętli typu. Tam, jeśli operacja jest zakończona, mapuje identyfikator operacji odczytu na wskaźnik wywołania zwrotnego + dane i wywołuje wywołanie zwrotne z informacją o zakończonej operacji.

void callback(void* buffer, int result, int fd, void* userData){
    if(result<=0){
    //done, free buffer and continue to normal processing
    }
    //use buffer

    int readID = async_read(fd, buffer, userData->buff_size);
    registerCallback(readId, callback, userData);
}

Oznacza to również, że każda funkcja, która mogłaby ostatecznie skorzystać z odczytu asynchronicznego, musiałaby być w stanie obsłużyć kontynuację asynchroniczną. Jest to nietrywialna zmiana w większości programów, pytasz ludzi próbujących dostać się do asynchronicznego C # na ten temat.


Jednak synchroniczne we / wy vs. asynchroniczne we / wy nie jest przyczyną ogólnego spowolnienia. Zamiana stron to także operacja, która musi czekać na IO. Program planujący po prostu przełączy się na inny program, który nie czeka na IO, jeśli taki istnieje ( IO czeka, gdy procesor jest bezczynny i trwa operacja IO ).

Prawdziwy problem polega na tym, że zarówno dysk twardy, jak i procesor używają tego samego kanału do komunikacji z pamięcią RAM ; magistrala pamięci. I chyba, że ​​używasz RAID, to jest tylko jeden dysk do pobierania danych. Sytuacja jest jeszcze gorsza, jeśli korzystasz również z aplikacji intensywnie korzystającej z grafiki, komunikacja z GPU również będzie zakłócać.

Innymi słowy, prawdziwym wąskim gardłem jest prawdopodobnie sprzęt, a nie oprogramowanie.

maniak zapadkowy
źródło
6
„Jednak synchroniczne we / wy vs. asynchroniczne we / wy nie jest przyczyną ogólnego spowolnienia”. Dlaczego więc zdecydowałeś się skoncentrować na tym stosunkowo zaawansowanym temacie, gdy pytanie dotyczy podstaw?
svick
1
Prawdopodobnie powinieneś coś wspomnieć o DMA
Alec Teal
2
Ciekawostka: istnieje naprawdę stary mechanizm, który pozwala programom robić coś innego podczas wykonywania operacji wejścia / wyjścia bez konieczności radzenia sobie z wywołaniami zwrotnymi; to się nazywa wątki .
user253751
2
Dobra dyskusja na temat zalet / wad synchronizacji / asynchronizacji we / wy. Ale czy jesteś pewien, że to jest powód spowolnienia? Ogólnie uważam, że spowolnienia przy dużym obciążeniu IO wynikają po pierwsze z powodu źle skonstruowanego oprogramowania, a gdy tak nie jest, to dlatego, że system używa pojedynczego, wolnego dysku (tj. Innego niż SSD) i wszystko próbuje uzyskać do niego dostęp jednocześnie . Winiłbym za wąskie gardło zdolność dysku do obsługi żądań, zanim obwiniłbym go za nasycenie magistrali pamięci. Potrzebujesz naprawdę wysokiej klasy pamięci, aby nasycić nowoczesną magistralę pamięci.
aroth
9

Miej wiarę, że przetwarzanie innych rzeczy podczas oczekiwania na I / O jest dość usprawnione, prawie tak uproszczone, jak to możliwe. Kiedy widzisz, że Twój komputer czeka tylko na We / Wy tylko 12,1% czasu, oznacza to, że w rzeczywistości robi wiele innych rzeczy równolegle. Gdyby naprawdę musiał czekać na operacje we / wy bez robienia czegokolwiek innego, czekałby przez 99,9% czasu, właśnie tak wolno działa operacja we / wy.

Jedynym sposobem na zrobienie większej liczby rzeczy równolegle jest przewidzenie, co użytkownik może zrobić dalej, a my nie jesteśmy jeszcze zbyt dobrzy w tego rodzaju przewidywaniach. Jeśli więc użytkownik wykona operację, która wymaga odczytania określonego sektora z dysku twardego, a sektor ten nie znajduje się już w pamięci podręcznej, system operacyjny rozpocznie bardzo długi proces odczytu tego sektora, i to postaram się sprawdzić, czy w międzyczasie jest coś jeszcze do zrobienia. Jeśli jest inny użytkownik, który chce innego sektora, będzie także umieszczał w kolejce to żądanie. W pewnym momencie wszystkie żądania zostały umieszczone w kolejce i nic nie możemy zrobić, tylko czekać na spełnienie pierwszego z nich, zanim będziemy mogli kontynuować. To tylko fakt z życia.

EDYTOWAĆ:

Znalezienie rozwiązania problemu wykonywania innych czynności podczas wykonywania operacji wejścia / wyjścia byłoby godnym podziwu wyczynem, ponieważ jednocześnie byłoby rozwiązaniem problemu wykonywania innych czynności w trybie bezczynności. To byłby niesamowity wyczyn, ponieważ oznaczałoby to, że znalazłbyś pracę dla swojego komputera, podczas gdy on nie ma żadnej.

Widzisz, właśnie tak się dzieje: twój komputer po prostu siedzi 99,99% czasu i nic nie robi. Kiedy dajesz mu coś do zrobienia, idzie i to robi. Jeśli to robi, musi czekać na I / O, siedzi tam i czeka. Jeśli ma coś innego do zrobienia podczas I / O, robi to również. Ale jeśli nie ma nic innego do roboty oprócz I / O, musi tam usiąść i czekać na zakończenie I / O. Nie ma innego sposobu na obejście tego niż rejestracja w SETI @ Home.

Mike Nakis
źródło
Cóż, 12,1% przykład pochodzi ze strony internetowej, a przykład pochodzi z serwera z 8 rdzeniami. Pomysł polegał na tym, że prawie jeden cały rdzeń był zarezerwowany dla tych operacji, z pewnością pozostałe rdzenie mogły robić wszystko i z 8 rdzeniami ma się dobrze, ale co jeśli masz tylko jeden rdzeń? : /
Arturas M
3
@ArturasM Albo źle zrozumiałeś, co mówi strona internetowa, albo autor strony coś źle zrozumiał. Komputer z tylko jednym rdzeniem spędziłby mniej czasu na oczekiwaniu na operacje we / wy (ponieważ wszystkie zadania, które nie czekają na operacje we / wy, które są wykonywane na innych rdzeniach, podczas gdy jeden rdzeń jest bezczynny, wszystkie musiałyby być wykonywane na jednym rdzeń). I / O zajmuje trochę czasu, bez względu na to, czy na to czekasz, czy nie - posiadanie czasu na to jest symptomem braku związku z tym czasem.
Random832
6

System operacyjny (chyba że jest to system osadzony na bardzo niskim poziomie lub coś podobnego egzotycznego) już się tym zajmuje: jeśli twoja aplikacja będzie musiała czekać na operacje we / wy, zwykle blokuje to operacje we / wy, a jakiś inny wątek lub aplikacja stanie się aktywny. Harmonogram decyduje, który z nich.

Tylko jeśli nie ma innego wątku lub aplikacji, która mogłaby być uruchomiona, faktycznie kumulujesz czas oczekiwania. W cytowanym artykule (dzięki @manlio za link) tak jest: masz 12,1% oczekiwania wobec 87,4% bezczynności, co oznacza, że ​​jeden rdzeń czeka na zakończenie operacji we / wy, podczas gdy reszta nic nie robi w ogóle. Daj temu systemowi coś do zrobienia, najlepiej kilka rzeczy, a procent oczekiwania powinien spaść.

Jednym z głównych celów dzisiejszego projektowania aplikacji jest zapewnienie, że nawet jeśli uruchomiona jest tylko jedna aplikacja, a nawet jeśli ta aplikacja w pewnym momencie czeka na operacje we / wy, aplikacja może nadal pracować z innym kawałkiem pracy. Wątki są jednym podejściem do tego, nieblokujące we / wy innym, ale w dużej mierze zależy od rodzaju pracy, którą wykonujesz, od tego, czy rzeczywiście możesz coś zrobić bez danych, na które czekasz.

w przypadku korzystania z systemu Linux, jeśli wykonujesz dłuższe zadania we / wy, system operacyjny staje się prawie bezużyteczny, dopóki nie zostaną ukończone.

Zazwyczaj oznacza to pewną sytuację związaną z We / Wy. Śmiem twierdzić, że system nie działa zbyt wolno, ponieważ nie jest w stanie wykonać wystarczającego przetwarzania procesora. Bardziej prawdopodobne jest, że jest powolny, ponieważ wiele rzeczy zależy od danych z dysku twardego, który jest wówczas zajęty. Mogą to być aplikacje, które chcesz uruchomić, ale które muszą załadować swoje pliki wykonywalne, pliki bibliotek, ikony, czcionki i inne zasoby. Mogą to być aplikacje, które już masz uruchomione, ale które zamieniły część pamięci i teraz potrzebują tej zamiany, aby kontynuować. Może to być jakiś demon, który z tego czy innego powodu uważa, że ​​nie tylko musi napisać wiersz do pliku dziennika, ale faktycznie opróżnić ten plik dziennika przed odpowiedzią na jakieś żądanie.

Możesz użyć narzędzi, takich jak, iotopaby zobaczyć, w jaki sposób przepustowość we / wy jest alokowana do procesów, i ioniceustawić priorytety we / wy dla procesów. Na przykład na komputerze stacjonarnym można zaklasyfikować całe przetwarzanie danych masowych do idleklasy planowania, tak aby w momencie, gdy niektóre aplikacje interaktywne potrzebują przepustowości we / wy, przetwarzanie zbiorcze zostaje zawieszone do czasu zakończenia aplikacji interaktywnej.

MvG
źródło
5

To zależy od kodu aplikacji. Przypuszczam, że twój kod działa w systemie Linux.

Możesz użyć wielowątkowości (np. Wątków POSIX ), aby wątki związane z obliczeniami wykonywały pewne obliczenia, podczas gdy inne wątki związane z IO wykonują IO (i czekają na to). Możesz nawet uruchomić w swojej aplikacji kilka procesów komunikujących się z komunikacją międzyprocesową (IPC), zobacz potok (7) , fifo (7) , socket (7) , unix (7) , shm_overview (7) , sem_overview (7) , mmap (2) , eventfd (2) i przeczytaj Zaawansowane programowanie w Linux itp.

Możesz użyć nieblokującego We / Wy , np. Pass O_NOBLOCKto open (2) etc etc etc ...; następnie musisz odpytać (2) i / lub użyć SIGIO sygnału (7) ... i obsłużyć EWOULDBLOCKbłąd z odczytu (2) itp.

Możesz użyć asynchronicznego We / Wy POSIX, patrz aio (7)

Aby uzyskać dostęp do plików, możesz podać wskazówki do pamięci podręcznej strony , np. Za pomocą madvise (2) po mmap (2) i posix_fadvise (2) ; zobacz także readahead specyficzny dla Linuksa (2)

Ale w końcu osiągniesz wąskie gardło sprzętowe (magistrala, pamięć RAM itp.). Zobacz także ionice (1)

Basile Starynkevitch
źródło
1

Dodaję inny punkt widzenia niż inne, może kontrowersyjny:

Typowy problem z systemami operacyjnymi Linux. Opóźnianie (Wyszukaj „Opóźnienie myszy w systemie Linux”). System Windows nie ma tego problemu. Mam podwójny rozruch Windows 7 i Linux Mint. Nawet podczas intensywnej pracy dysku w systemie Windows system Windows jest płynny, mysz porusza się normalnie. W Linuksie nie jest to odczuwalne, więc wygładza się, a mysz czasami opóźnia się nawet podczas normalnego przeglądania sieci.

Prawdopodobnie dlatego, że inna filozofia i historia tych dwóch systemów. Windows od samego początku jest przeznaczony dla zwykłych użytkowników, głównie z graficznych systemów operacyjnych. A dla użytkowników systemu Windows nierównomierne zachowanie systemu i zatrzymywanie się myszy to sygnał, że coś jest nie tak. Dlatego programiści Microsofts ciężko pracowali nad zaprojektowaniem całego systemu, aby zminimalizować przypadki, gdy system wydaje się być powolny. W przeciwieństwie do Linuksa początkowo nie jest systemem graficznym, pulpit jest tylko dodatkiem zewnętrznym. Linux jest przeznaczony głównie dla hakerów korzystających z wiersza poleceń. Realizuj filozofię. Linux po prostu nie jest zaprojektowany do płynnego zachowania, uczucia nie mają tutaj znaczenia.

Uwaga: nie twierdzę, że Windows jest lepszy niż Linux, mówię, że mają one po prostu inną ogólną filozofię, co w złożonym środowisku może prowadzić do różnych zachowań / odczuć na wysokim poziomie tych systemów.

użytkownik3123061
źródło
Opóźnienia myszy w Linuksie można by prawdopodobnie uniknąć lub zmniejszyć poprzez staranną konfigurację systemu (tj. Używając nice& ionicena głodnych procesach). Używam Linuksa i prawie nigdy nie doświadczyłem tego opóźnienia myszy w Linuksie (z wyjątkiem przeciążenia mojego komputera ...)
Basile Starynkevitch,
BTW, Linux to głównie system operacyjny serwera.
Basile Starynkevitch
Zauważyłem, że miałem doświadczenie z interfejsem użytkownika i opóźnieniem myszy w systemie Windows 7, nawet w czasach, gdy Menedżer zadań i Monitor zasobów wskazywały na niskie zużycie pamięci oraz małą aktywność procesora i dysku.
8bittree