Помислете за приложение, което е обвързано с процесора, но също така има високопроизводителни I/O изисквания.
Сравнявам файлов I/O на Linux с Windows и не виждам как epoll изобщо ще помогне на Linux програма. Ядрото ще ми каже, че файловият дескриптор е „готов за четене“, но все пак трябва да извикам блокирането read(), за да получа данните си, и ако искам да прочета мегабайти, е доста ясно, че това ще блокира.
В Windows мога да създам манипулатор на файл с набор OVERLAPPED и след това да използвам неблокиращ I/O и да получавам известия, когато I/O завърши, и да използвам данните от тази функция за завършване. Не трябва да прекарвам време на стенен часовник на ниво приложение в чакане на данни, което означава, че мога прецизно да настроя броя на нишките си спрямо броя на ядрата си и да получа 100% ефективно използване на процесора.
Ако трябва да емулирам асинхронен I/O на Linux, тогава трябва да разпределя известен брой нишки, за да направя това, и тези нишки ще прекарат малко време в извършване на CPU неща и много време в блокиране за I/O, освен това ще има допълнителни разходи в съобщенията към/от тези теми. По този начин или ще се абонирам прекалено много, или ще използвам недостатъчно процесорните си ядра.
Разгледах mmap() + madvise() (WILLNEED) като „async I/O на бедния човек“, но все още не стига дотам, защото не мога да получа известие, когато е готово -- имам да "позная" и ако позная "погрешно", в крайна сметка ще блокирам достъпа до паметта, чакайки данните да дойдат от диска.
Linux изглежда има началото на async I/O в io_submit и изглежда също така има имплементация на POSIX aio в потребителско пространство, но това е така от известно време и не познавам никой, който би гарантирал за тези системи за критични , приложения с висока производителност.
Моделът на Windows работи приблизително така:
- Издайте асинхронна операция.
- Свържете асинхронната операция с конкретен I/O порт за завършване.
- Изчакайте операциите да завършат на този порт
- Когато I/O приключи, нишката, чакаща на порта, се деблокира и връща препратка към чакащата I/O операция.
Стъпки 1/2 обикновено се извършват като едно нещо. Стъпки 3/4 обикновено се извършват с набор от работни нишки, а не (непременно) същата нишка, която издава I/O. Този модел е донякъде подобен на модела, осигурен от boost::asio, с изключение на това, че boost::asio всъщност не ви дава асинхронен базиран на блок (диск) I/O.
Разликата с epoll в Linux е, че в стъпка 4 все още не се е случил вход/изход - тя издига стъпка 1, за да дойде след стъпка 4, което е "назад", ако знаете точно какво имате нужда вече.
След като програмирах голям брой вградени, настолни и сървърни операционни системи, мога да кажа, че този модел на асинхронен I/O е много естествен за определени видове програми. Освен това е с много висока пропускателна способност и ниски разходи. Мисля, че това е един от оставащите реални недостатъци на I/O модела на Linux на ниво API.
select
/poll
/epoll
/kqueue
, тогава би било МНОГО необичайно да продължите с блокиране наread
/write
, когато получите известие, че файлов дескриптор е готов. Почти със сигурност искате да направите неблокиращоread
илиwrite
там. - person Celada   schedule 17.11.2012