Re[3]: Асинхронный файловый ввод-вывод
От: Pzz Россия https://github.com/alexpevzner
Дата: 16.06.16 14:43
Оценка:
Здравствуйте, 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) с нулевым таймаутом.

Как-то примерно так...
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.