Co oznaczają pojęcia „związany z procesorem” i „związany z I / O”?


Odpowiedzi:


452

To dość intuicyjne:

Program jest związany z procesorem, jeśli działałby szybciej, gdyby procesor był szybszy, tzn. Spędza większość czasu po prostu wykorzystując procesor (wykonując obliczenia). Program, który oblicza nowe cyfry π, zwykle jest związany z procesorem, to po prostu chrupiące liczby.

Program jest powiązany z operacjami we / wy, jeśli działałby szybciej, gdyby podsystem we / wy był szybszy. To, który dokładnie system I / O ma na myśli, może się różnić; Zazwyczaj kojarzę go z dyskiem, ale oczywiście powszechna jest także praca w sieci lub komunikacja. Program, który przegląda ogromny plik w poszukiwaniu niektórych danych, może zostać powiązany z operacjami wejścia / wyjścia, ponieważ wąskim gardłem jest wówczas odczyt danych z dysku (w rzeczywistości ten przykład jest obecnie trochę staromodny z setkami MB / s przychodzące z dysków SSD).


W jaki sposób wiąże się to ze zrozumieniem komunikacji HTTP na urządzeniu mobilnym? Widziałem gwałtowny wzrost użycia procesora przy korzystaniu z operacji java.nio .
IgorGanapolsky

I / O to „wejście / wyjście”.
Towarzysz Che

246

Ograniczenie procesora oznacza szybkość, z jaką proces postępuje, jest ograniczona szybkością procesora. Zadanie, które wykonuje obliczenia na małym zestawie liczb, na przykład mnożąc małe macierze, prawdopodobnie będzie związane z procesorem.

Ograniczenie We / Wy oznacza szybkość, z jaką proces postępuje, jest ograniczona prędkością podsystemu We / Wy. Zadanie przetwarzające dane z dysku, na przykład zliczanie liczby wierszy w pliku, może być prawdopodobnie związane z operacjami we / wy.

Powiązanie z pamięcią oznacza szybkość, z jaką proces postępuje, jest ograniczona ilością dostępnej pamięci i szybkością dostępu do pamięci. Zadanie, które przetwarza duże ilości danych w pamięci, na przykład mnożenie dużych macierzy, prawdopodobnie będzie związane z pamięcią.

Ograniczona pamięć podręczna oznacza szybkość, z jaką postęp procesu jest ograniczony przez ilość i szybkość dostępnej pamięci podręcznej. Zadanie, które po prostu przetwarza więcej danych niż mieści się w pamięci podręcznej, zostanie powiązane z pamięcią podręczną.

Ograniczenie wejścia / wyjścia byłoby wolniejsze niż ograniczenie pamięci byłoby wolniejsze niż ograniczenie pamięci podręcznej byłoby wolniejsze niż ograniczenie procesora.

Rozwiązaniem problemu związania we / wy niekoniecznie jest uzyskanie większej ilości pamięci. W niektórych sytuacjach algorytm dostępu można zaprojektować z uwzględnieniem ograniczeń we / wy, pamięci lub pamięci podręcznej. Zobacz Cache Oblivious Algorytmy .


72

Wielowątkowość

W tej odpowiedzi zbadam jeden ważny przypadek użycia rozróżnienia między pracą związaną z CPU a IO: podczas pisania kodu wielowątkowego.

Przykład związany z We / Wy pamięci RAM: Suma wektorowa

Rozważmy program sumujący wszystkie wartości jednego wektora:

#define SIZE 1000000000
unsigned int is[SIZE];
unsigned int sum = 0;
size_t i = 0;
for (i = 0; i < SIZE; i++)
    /* Each one of those requires a RAM access! */
    sum += is[i]

Równoważenie tego przez równe podzielenie macierzy dla każdego z rdzeni ma ograniczoną przydatność na popularnych współczesnych komputerach stacjonarnych.

Na przykład na moim Ubuntu 19.04, laptop Lenovo ThinkPad P51 z procesorem: procesor Intel Core i7-7820HQ (4 rdzenie / 8 wątków), pamięć RAM: 2x Samsung M471A2K43BB1-CRC (2x 16GiB) Otrzymuję wyniki takie jak to:

wprowadź opis zdjęcia tutaj

Wykres danych .

Zauważ jednak, że istnieje duża wariancja między uruchomieniami. Ale nie mogę znacznie zwiększyć rozmiaru tablicy, ponieważ mam już 8GiB i nie mam dzisiaj ochoty na statystyki dla wielu przebiegów. Wydawało się to jednak typowym uruchomieniem po wykonaniu wielu ręcznych uruchomień.

Kod testu porównawczego:

Nie znam wystarczającej architektury komputerowej, aby w pełni wyjaśnić kształt krzywej, ale jedno jest jasne: obliczenia nie stają się 8-krotnie szybsze, niż naiwnie oczekiwałem, ponieważ używam wszystkich moich 8 wątków! Z jakiegoś powodu 2 i 3 wątki były optymalne, a dodawanie kolejnych powoduje, że wszystko jest znacznie wolniejsze.

Porównaj to z pracą związaną z procesorem, która faktycznie staje się 8-krotnie szybsza: co oznaczają „rzeczywisty”, „użytkownik” i „sys” na wyjściu czasu (1)?

Powodem jest to, że wszystkie procesory współużytkują jedną szynę pamięci łączącą się z pamięcią RAM:

CPU 1   --\    Bus    +-----+
CPU 2   ---\__________| RAM |
...     ---/          +-----+
CPU N   --/

więc magistrala pamięci szybko staje się wąskim gardłem, a nie procesorem.

Dzieje się tak, ponieważ dodanie dwóch liczb zajmuje jeden cykl procesora, odczyty pamięci zajmują około 100 cykli procesora w sprzęcie z 2016 roku.

Praca procesora wykonywana na bajt danych wejściowych jest zbyt mała i nazywamy to procesem związanym z We / Wy.

Jedynym sposobem na dalsze przyspieszenie tego obliczenia byłoby przyspieszenie dostępu do poszczególnych pamięci za pomocą nowego sprzętu pamięci, np . Pamięci wielokanałowej .

Na przykład aktualizacja do szybszego zegara procesora nie byłaby bardzo przydatna.

Inne przykłady

Jak dowiedzieć się, czy jesteś związany procesorem czy we / wy

IO niezwiązane z pamięcią RAM, jak dysk, sieć ps aux:, a następnie sprawdź jeśli CPU% / 100 < n threads. Jeśli tak, jesteś związany We / Wy, np. Blokowanie readtylko czeka na dane, a program planujący pomija ten proces. Następnie użyj innych narzędzi, takich jak sudo iotopdecyzja, które dokładnie jest problemem.

Lub, jeśli wykonanie jest szybkie i sparametryzujesz liczbę wątków, możesz to łatwo zauważyć, ponieważ timewydajność poprawia się wraz ze wzrostem liczby wątków dla pracy związanej z procesorem: Co oznaczają słowa „rzeczywisty”, „użytkownik” i „sys” w wyjście czasu (1)?

Związany z RAM-IO: trudniej powiedzieć, ponieważ czas oczekiwania RAM jest uwzględniany w CPU%pomiarach, patrz także:

Niektóre opcje:

GPU

Procesory graficzne mają wąskie gardło we / wy podczas pierwszego przesyłania danych wejściowych ze zwykłej pamięci RAM odczytywalnej przez procesor do GPU.

Dlatego procesory graficzne mogą być lepsze niż procesory tylko dla aplikacji związanych z procesorem.

Jednak po przesłaniu danych do GPU może działać na tych bajtach szybciej niż procesor, ponieważ GPU:

  • ma większą lokalizację danych niż większość systemów CPU, dzięki czemu dostęp do danych jest szybszy dla niektórych rdzeni niż dla innych

  • wykorzystuje równoległość danych i opóźnia poświęcenie, po prostu pomijając wszelkie dane, które nie są gotowe do natychmiastowej obsługi.

    Ponieważ GPU musi działać na dużych równoległych danych wejściowych, lepiej jest po prostu przejść do następnych danych, które mogą być dostępne, zamiast czekać na pojawienie się bieżących danych i zablokować wszystkie inne operacje, tak jak procesor w większości przypadków

Dlatego procesor graficzny może być szybszy niż procesor, jeśli aplikacja:

  • może być wysoce zrównoleglony: różne fragmenty danych mogą być traktowane oddzielnie od siebie w tym samym czasie
  • wymaga wystarczająco dużej liczby operacji na bajt wejściowy (w przeciwieństwie do np. dodawania wektora, który wykonuje tylko jeden dodawanie na bajt)
  • istnieje duża liczba bajtów wejściowych

Te opcje projektowania pierwotnie dotyczyły zastosowania renderowania 3D, których główne kroki są pokazane w Co to są shadery w OpenGL i do czego są nam potrzebne?

  • moduł cieniujący wierzchołek: pomnożenie wiązki wektorów 1x4 przez macierz 4x4
  • moduł cieniujący fragmentów: oblicz kolor każdego piksela trójkąta na podstawie jego względnej pozycji względem trójkąta

i doszliśmy do wniosku, że te aplikacje są związane z procesorem.

Wraz z pojawieniem się programowalnego GPGPU możemy zaobserwować kilka aplikacji GPGPU, które służą jako przykłady operacji związanych z procesorem:

Zobacz też:

CPython Global Intepreter Lock (GIL)

W ramach krótkiego studium przypadku chcę zwrócić uwagę na globalną blokadę interpretera (GIL) w Pythonie: Co to jest globalna blokada tłumacza (GIL) w CPython?

Ten szczegół implementacji CPython uniemożliwia wielu wątkom Pythona wydajne korzystanie z pracy związanej z procesorem. Dokumenty CPython mówią:

Szczegóły implementacji CPython: W CPython, ze względu na globalną blokadę interpretera, tylko jeden wątek może wykonać kod Pythona jednocześnie (nawet jeśli niektóre biblioteki zorientowane na wydajność mogą obejść to ograniczenie). Jeśli chcesz, aby aplikacja lepiej wykorzystywała zasoby obliczeniowe maszyn wielordzeniowych, zalecamy użycie multiprocessinglub concurrent.futures.ProcessPoolExecutor. Jednak wątkowanie jest nadal odpowiednim modelem, jeśli chcesz uruchamiać wiele zadań związanych z operacjami we / wy jednocześnie.

Dlatego mamy tutaj przykład, w którym zawartość związana z procesorem nie jest odpowiednia, a związana jest z operacjami we / wy.


1
Człowieku, jak udaje ci się być tak kompetentnym i napisać coś takiego?
Mikayil Abdullayev

1
@MikayilAbdullayev dzięki! Zwykle odpowiadam tylko na „ważne pytania” i często do nich wracam, gdy uczę się nowych, istotnych rzeczy.
Ciro Santilli 13 冠状 病 六四 事件 法轮功

31

Ograniczenie procesora oznacza, że ​​program ma wąskie gardło ze strony procesora lub jednostki centralnej, natomiast ograniczenie wejścia / wyjścia oznacza, że ​​program jest wąskie gardło przez wejścia / wyjścia lub wejścia / wyjścia, takie jak odczyt lub zapis na dysk, sieć itp.

Ogólnie, optymalizując programy komputerowe, próbuje się znaleźć wąskie gardło i go wyeliminować. Wiedza o tym, że twój program jest związany z procesorem, pomaga, aby niepotrzebnie nie optymalizować czegoś innego.

[Przez „wąskie gardło” mam na myśli rzecz, która powoduje, że twój program działa wolniej niż w innym przypadku.]


21

Inny sposób sformułowania tego samego pomysłu:

  • Jeśli przyspieszenie procesora nie przyspieszyć swój program, to może być I / O związany.

  • Jeśli przyspieszenie operacji we / wy (np. Użycie szybszego dysku) nie pomaga, program może być związany z procesorem.

(Użyłem „może być”, ponieważ musisz wziąć pod uwagę inne zasoby. Pamięć jest jednym z przykładów).


11

Gdy program czeka na operacje we / wy (tj. Odczyt / zapis dysku lub odczyt / zapis sieciowy itp.), Procesor może wykonywać inne zadania, nawet jeśli program zostanie zatrzymany. Szybkość twojego programu będzie zależeć głównie od tego, jak szybko może nastąpić IO, a jeśli chcesz go przyspieszyć, musisz przyspieszyć I / O.

Jeśli twój program wykonuje wiele instrukcji programu i nie czeka na operacje wejścia / wyjścia, mówi się, że jest związany z procesorem. Przyspieszenie procesora przyspieszy działanie programu.

W obu przypadkach kluczem do przyspieszenia programu może nie być przyspieszenie sprzętu, ale optymalizacja programu w celu zmniejszenia potrzebnej liczby operacji wejścia / wyjścia lub procesora we / wy, podczas gdy procesor wymaga dużego obciążenia procesora rzeczy.


6

Powiązanie We / Wy odnosi się do stanu, w którym czas potrzebny do ukończenia obliczeń jest określany głównie przez okres oczekiwania na zakończenie operacji wejścia / wyjścia.

Jest to przeciwieństwo zadania związanego z procesorem. Ta okoliczność powstaje, gdy szybkość żądania danych jest mniejsza niż szybkość ich zużywania lub, innymi słowy, spędza się więcej czasu na żądaniu danych niż na ich przetwarzaniu.


6

Procesy związane z operacjami we / wy: spędzaj więcej czasu na wykonywaniu operacji we / wy niż na obliczeniach, mają wiele krótkich serii procesorów. Procesy związane z procesorem: spędzaj więcej czasu na obliczeniach, kilka bardzo długich serii procesorów


2

Zobacz, co mówi Microsoft.

Rdzeniem programowania asynchronicznego są obiekty Task i Task, które modelują operacje asynchroniczne. Są obsługiwane przez asynchronię i czekają na słowa kluczowe. Model jest w większości przypadków dość prosty:

  • W przypadku kodu związanego z operacjami we / wy oczekuje się operacji, która zwróci zadanie lub zadanie wewnątrz metody asynchronicznej.

  • W przypadku kodu związanego z procesorem oczekuje się operacji, która jest uruchamiana w wątku w tle za pomocą metody Task.Run.

Oczekiwane słowo kluczowe to miejsce magii. Daje kontrolę nad wywołującym metodę, która jest wykonywana w oczekiwaniu, i ostatecznie pozwala na reagowanie interfejsu użytkownika lub elastyczność usługi.

Przykład związany z We / Wy: Pobieranie danych z usługi internetowej

private readonly HttpClient _httpClient = new HttpClient();

downloadButton.Clicked += async (o, e) =>
{
    // This line will yield control to the UI as the request
    // from the web service is happening.
    //
    // The UI thread is now free to perform other work.
    var stringData = await _httpClient.GetStringAsync(URL);
    DoSomethingWithData(stringData);
};

Przykład związany z procesorem: Przeprowadzanie obliczeń dla gry

private DamageResult CalculateDamageDone()
{
    // Code omitted:
    //
    // Does an expensive calculation and returns
    // the result of that calculation.
}

calculateButton.Clicked += async (o, e) =>
{
    // This line will yield control to the UI while CalculateDamageDone()
    // performs its work.  The UI thread is free to perform other work.
    var damageResult = await Task.Run(() => CalculateDamageDone());
    DisplayDamage(damageResult);
};

Przykłady powyżej pokazały, jak można używać asynchronizacji i oczekiwać na pracę związaną z We / Wy i procesor. Jest to klucz, który można zidentyfikować, gdy zadanie, które należy wykonać, jest związane z operacjami we / wy lub procesorem, ponieważ może to znacznie wpłynąć na wydajność kodu i potencjalnie może prowadzić do niewłaściwego użycia niektórych konstrukcji.

Oto dwa pytania, które powinieneś zadać przed napisaniem kodu:

Czy Twój kod będzie „czekał” na coś, na przykład dane z bazy danych?

  • Jeśli twoja odpowiedź brzmi „tak”, to twoja praca jest związana z operacjami wejścia / wyjścia.

Czy Twój kod będzie wykonywał bardzo drogie obliczenia?

  • Jeśli odpowiedziałeś „tak”, to twoja praca jest związana z procesorem.

Jeśli twoja praca jest związana z operacjami we / wy, użyj asynchronizacji i poczekaj bez Task.Run . Nie należy używać biblioteki zadań równoległych. Przyczynę tego opisano w artykule Async in Depth .

Jeśli twoja praca jest związana z procesorem i zależy ci na responsywności, użyj asynchronizacji i poczekaj, ale odrodzenie pracy w innym wątku za pomocą Task.Run. Jeśli praca jest odpowiednia dla współbieżności i równoległości, należy również rozważyć użycie biblioteki zadań równoległych .


2

Aplikacja jest związana z procesorem, gdy wydajność arytmetyczna / logiczna / zmiennoprzecinkowa (A / L / FP) podczas wykonywania jest najczęściej zbliżona do teoretycznej wydajności szczytowej procesora (dane dostarczone przez producenta i określone przez właściwości procesor: liczba rdzeni, częstotliwość, rejestry, ALU, FPU itp.).

Wydajność podglądu jest bardzo trudna do osiągnięcia w rzeczywistych aplikacjach, ponieważ nie jest to niemożliwe. Większość aplikacji uzyskuje dostęp do pamięci w różnych częściach wykonania, a procesor nie wykonuje operacji A / L / FP podczas kilku cykli. Nazywa się to ograniczeniem von Neumanna ze względu na odległość między pamięcią a procesorem.

Jeśli chcesz być blisko wydajności szczytowej procesora, strategią może być próba ponownego wykorzystania większości danych w pamięci podręcznej, aby uniknąć wymagania danych z pamięci głównej. Algorytmem wykorzystującym tę funkcję jest mnożenie macierzy i macierzy (jeśli obie macierze można zapisać w pamięci podręcznej). Dzieje się tak, ponieważ jeśli macierze mają rozmiar n x n, należy wykonać 2 n^3operacje wykorzystujące tylko 2 n^2liczby danych FP. Z drugiej strony, dodawanie macierzy, na przykład, jest mniej związane z procesorem lub bardziej związane z pamięcią niż mnożenie macierzy, ponieważ wymaga tylko n^2FLOP z tymi samymi danymi.

Na poniższym rysunku pokazano FLOP uzyskane naiwnymi algorytmami dodawania macierzy i mnożenia macierzy w procesorze Intel i5-9300H:

Porównanie FLOP między dodawaniem macierzy a mnożeniem macierzy

Należy zauważyć, że zgodnie z oczekiwaniami wydajność mnożenia macierzy jest większa niż dodawanie macierzy. Wyniki te można odtworzyć, uruchamiając test/gemmi test/matadddostępne w tym repozytorium .

Sugeruję również obejrzenie filmu wideo o tym działaniu autorstwa J. Dongarry.


1

Proces związany z We / Wy: - Jeśli większość czasu życia procesu jest spędzana w stanie we / wy, wówczas proces jest związany z procesem we / wy. Przykład: -kalkulator, przeglądarka internetowa

Proces związany z procesorem: - Jeśli większość czasu życia procesu jest spędzana w jednostce centralnej, to jest to proces związany z jednostką centralną.


8
W jaki sposób kalkulator byłby procesem związanym z IO? Z pewnością będzie to związane z procesorem. Jeśli Twój kalkulator spędza większość czasu na blokowaniu dostępu do sieci lub dysku, sugeruję, że coś jest z nim nie tak.
rickerbh

6
Myślałem, że przykład kalkulatora jest jasny: przez większość czasu czeka on na naciśnięcie przycisku przez użytkownika, a więc czeka na we / wy.
psp

1
@psp ma rację, ale przykład kalkulatora nadal jest powierzchownie trudny do zauważenia jako związany ze względu na swoją nazwę „kalkulator”. Oznacza to, że głównym celem programu jest wykonywanie długich obliczeń procesora, ale jeśli spojrzysz na swój kalkulator na pulpicie, jest on bardzo prosty i wykonuje tylko obliczenia, których wykonanie zajmuje kilka nanosekund. Dlatego przez większość czasu czeka na dane wejściowe użytkownika, którym jest IO.
Calicoder
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.