Книга: Разработка приложений в среде Linux. Второе издание

13.1.6 Сравнение poll() и epoll

13.1.6 Сравнение poll() и epoll

Методы poll() и epoll существенно отличаются; poll() хорошо стандартизован, но плохо масштабируется, в то время как epoll существует только в Linux, но очень хорошо масштабируется. Приложения, наблюдающие за небольшим количеством файловых дескрипторов и переносимости величин, должны использовать poll(), но любому приложению, которому необходимо контролировать большое количество дескрипторов, лучше применять epoll, даже если ему нужно поддерживать poll() для других платформ.

Отличия в производительности двух методов поразительны. Чтобы продемонстрировать, насколько лучше масштабируется epoll, в коде poll-vs-epoll.с измеряется количество системных вызовов poll() и epoll_wait(), которые можно создать за одну секунду для наборов файловых дескрипторов разных размеров (количество файловых дескрипторов для помещения в набор задается в командной строке). Каждый файловый дескриптор ссылается на считывающую часть канала, и они создаются с помощью dup2().

В табл. 13.1 суммируются результаты запуска poll-vs-epoll.с для установленных размеров диапазоном от одного до 100 000 файловых дескрипторов[82]. В то время как количество системных вызовов в секунду резко падает для poll(), оно остается почти постоянным для epoll[83]. Как поясняет эта таблица, epoll добавляет в систему намного меньше нагрузки, чем poll(), и в результате гораздо лучше масштабируется.

Таблица 13.1. Результаты сравнения poll() и epoll()

Файловые дескрипторы poll() epoll()
1 310063 714848
10 140842 726108
100 25866 726659
1000 3343 729072
5000 612 718424
10000 300 730483
25000 108 717097
50000 38 729746
100000 18 712301

  1: /* poll-vs-epoll.с */
  2:
  3: #include <errno.h>
  4: #include <fcntl.h>
  5: #include <stdio.h>
  6: #include <sys/epoll.h>
  7: #include <sys/poll.h>
  8: #include <sys/signal.h>
  9: #include <unistd.h>
 10: #include <sys/resource.h>
 11: #include <string.h>
 12: #include <stdlib.h>
 13:
 14: #include <sys/select.h>
 15:
 16: int gotAlarm;
 17:
 18: void catch(int sig) {
 19:  gotAlarm = 1;
 20: }
 21:
 22: #define OFFSET 10
 23:
 24: int main(int argc, const char ** argv) {
 25:  int pipeFds[2];
 26:  int count;
 27:  int numFds;
 28:  struct pollfd * pollFds;
 29:  struct epoll_event event;
 30:  int epfd;
 31:  int i;
 32:  struct rlimit lim;
 33:  char * end;
 34:
 35:  if (!argv[1]) {
 36:   fprintf(stderr, "ожидалось числоn");
 37:   return 1;
 38:  }
 39:
 40:  numFds = strtol(argv[1], &end, 0);
 41:  if (*end) {
 42:   fprintf(stderr, "ожидалось числоn");
 43:   return 1;
 44:  }
 45:
 46:  printf("Запуск теста для %d файловых дескрипторов.n", numFds);
 47:
 48:  lim.rlim_cur = numFds + OFFSET;
 49:  lim.rlim_max = numFds + OFFSET;
 50:  if (setrlimit(RLIMIT_NOFILE, &lim)) {
 51:   perror("setrlimit");
 52:   exit(1);
 53:  }
 54:
 55:  pipe(pipeFds);
 56:
 57:  pollFds = malloc(sizeof (*pollFds) * numFds);
 58:
 59:  epfd = epoll_create(numFds);
 60:  event.events = EPOLLIN;
 61:
 62:  for (i = OFFSET; i < OFFSET + numFds; i++) {
 63:   if (dup2(pipeFds[0], i) != i) {
 64:    printf("сбой в %d: %sn", i, strerror(errno));
 65:    exit(1);
 66:   }
 67:
 68:   pollFds[i - OFFSET].fd = i;
 69:   pollFds[i - OFFSET].events = POLLIN;
 70:
 71:   event.data.fd = i;
 72:   epoll_ctl(epfd, EPOLL_CTL_ADD, i, &event);
 73:  }
 74:
 75:  /* с помощью signal выяснить, когда время истекло */
 76:  signal(SIGALRM, catch);
 77:
 78:  count = 0;
 79:  gotAlarm = 0;
 80:  alarm(1);
 81:  while (!gotAlarm) {
 82:   poll(pollFds, numFds, 0);
 83:   count++;
 84:  }
 85:
 86:  printf("Вызовов poll() в секунду: %dn", count);
 87:
 88:  alarm(1);
 89:
 90:  count = 0;
 91:  gotAlarm = 0;
 92:  alarm(1);
 93:  while (!gotAlarm) {
 94:   epoll_wait(epfd, &event, 1, 0);
 95:   count++;
 96:  }
 97:
 98:  printf("Вызовов epoll() в секунду: %dn", count);
 99:
100:  return 0;
101: }

Оглавление книги


Генерация: 8.810. Запросов К БД/Cache: 3 / 0
поделиться
Вверх Вниз