Здравствуйте, chaotic-kotik, Вы писали:
Pzz>>В общем, надо экспериментировать, дает ли асинхронный ввод-вывод какой-либо выигрыш в вашей конкретной задаче, или наоборот, проигрывает, или получаются близкие результаты. Причем у скедулера ввода-вывода есть свои ручки для настройки, экспериментировать надо, крутя эти ручки. И для SSD ответ будет совершенно другим, чем для механического диска.
CK>Я делаю оптимизацию под SSD + есть кое какие требования, которые проще всего реализовать через O_DIRECT+асинхронность.
Мне кажется, для SSD использование асинхронного ввода-вывода не даст сколь либо ощутимой оптимизации.
Pzz>>В третьих, у нативного AIO интерфейс такой, что, на первый взгляд, его невозможно совместить в одном потоке с poll/select/eventfd. Потому что один поток может ждать либо io_getevents(), либо poll(), но не одновременно. Но если некоторое время подумать головой, и потом встать на уши, то совместить удается. Если кому интересно, могу отдельным письмом рассказать, как это сделать.
CK>Мне интересно, т.к. подозреваю что буду писать свой велосипед. Нельзя просто в тему запостить?
1) Под ниткой здесь и далее я имею ввиду ту нитку, в которой крутится event loop, а под сокетом — файловый дескриптор, которым нам интересен на предмет poll() (но он может быть и не сокетом, а пайпом и т.п.). Можно сделать несколько таких ниток, но каждый сокет должен быть привязан к своей нитке.
2) В нитке маскируем SIGIO (man pthread_sigmask)
3) Все файловые сокеты, которые мы собираемся poll()'ить, настраиваем так, чтобы от них приходил SIGIO. См. man fcntl на предмет F_SETSIG, F_SETOWN_EX, O_ASYNC и O_NONBLOCK. Я писал это под более старое ядро, чем сегодняшние, поэтому работающего куска кода не покажу, но в мане вроде все просто. В общем, надо, чтобы приходил SIGIO, причем конкретно той нитке, которая будет ждать, а не первой попавшейся
4) Ожидание выглядит следующим образом:
volatile bool got_signal = false;
sigjmp_buf jmp_buf;
if (sigsetjmp(jmp_buf, true))
got_signal = true;
else {
pthread_sigmask(...); // Размаскируем SIGIO
io_getevents(...); // Ждем дискового ввода-вывода
pthread_sigmask(...); // Маскируем SIGIO
}
5) Обработчик SIGIO делает siglongjmp(jmp_buf, 1);
6) Поскольку в случае прихода сигнала мы не можем знать, успели ли мы вызвать io_getevents(), то значение, которое эта функция возвращает, для нас бессмысленно, и мы вынуждены сканировать массив struct io_event после вызова io_getevents(), заполнив его нулями до вызова, чтобы понять, успел ли он вернуть сколько-нибудь событий.
7) Если после выхода из ожидания got_signal = true, разбираемся с сокетами используя любой механизм (select/poll/epoll) с нулевым таймаутом.
Как-то примерно так...