Oglądałem tę rozmowę o wdrażaniu Async IO w Rust, a Carl wymienia dwa potencjalne modele. Gotowość i realizacja.
Model gotowości:
- informujesz jądro, że chcesz czytać z gniazda
- rób inne rzeczy przez jakiś czas…
- jądro informuje, kiedy gniazdo jest gotowe
- czytasz (wypełniasz bufor)
- rób co potrzebujesz
- zwolnij bufor (dzieje się automatycznie z Rust)
Model wykonania:
- alokujesz bufor dla jądra do wypełnienia
- rób inne rzeczy przez jakiś czas…
- jądro informuje, kiedy bufor został zapełniony
- rób wszystko, co potrzebujesz z danymi
- zwolnij bufor
W przykładzie Carla, w którym zastosowano model gotowości, można było iterować po wypełnieniu gotowych gniazd i zwolnieniu globalnego bufora, co wydaje się, że zużyłoby znacznie mniej pamięci.
Teraz moje założenia:
Pod maską (w przestrzeni jądra), gdy mówi się, że gniazdo jest „gotowe”, dane już istnieją. Wszedł do gniazda przez sieć (lub skądkolwiek), a system operacyjny przechowuje dane.
To nie tak, że alokacja pamięci magicznie nie występuje w modelu gotowości. Po prostu system operacyjny ją od ciebie odciąga. W modelu Completion system operacyjny prosi o przydzielenie pamięci, zanim dane faktycznie wpłyną, i oczywiste jest, co się dzieje.
Oto moja zmieniona wersja Modelu gotowości:
- informujesz jądro, że chcesz czytać z gniazda
- rób inne rzeczy przez jakiś czas…
- POPRAWKA: dane przychodzą do systemu operacyjnego (jakieś miejsce w pamięci jądra)
- jądro informuje, że gniazdo jest gotowe
- czytasz (wypełniasz inny bufor oddzielnie od bufora jądra abover (lub dostajesz do niego wskaźnik?))
- rób co potrzebujesz
- zwolnij bufor (dzieje się automatycznie z Rust)
/ Moje założenia
Podoba mi się to, że program przestrzeni użytkownika jest niewielki, ale chciałem tylko wyjaśnić, co tak naprawdę dzieje się tutaj. Nie widzę, aby jeden model z natury zużywałby mniej pamięci lub obsługiwał wyższy poziom współbieżnych operacji we / wy. Bardzo chciałbym usłyszeć myśli i głębsze wyjaśnienie tego.