01
21

epoll,select,poll-無責任效能評測

有天在看Linux系統程式設計時,翻到其中一頁關於linux2.6引進的epoll事件輪詢界面,在好奇心的驅使下,就想動手寫程式跑跑看epoll,select和poll到底那個效能比較好

而我測試的方法是利用這三個API寫一個小的web server,再用Apache Benchmark測試,並以測試的結果比較這三個效能的優劣,我下的apache benchmark指令為” ab -c 50 -n 500 http://192.168.15.25:5050/” ,結果請見如下

[select]
50個人同時連線的情況下,每秒鐘的Request次數:    130.61 [#/sec] (mean)
50個人裡「平均」每個人感受到的回應時間    :    382.812 [ms] (mean)

[poll]
50個人同時連線的情況下,每秒鐘的Request次數:    101.31 [#/sec] (mean)
50個人裡「平均」每個人感受到的回應時間    :    493.554 [ms] (mean)

[epoll]
50個人同時連線的情況下,每秒鐘的Request次數:    126.85 [#/sec] (mean)
50個人裡「平均」每個人感受到的回應時間    :    394.171 [ms] (mean)

從上面的結果可以看到,select好像比epoll好一點點,不曉得是不是我把epoll event array設太大的關係,本文章所寫的程式碼可在這邊下載(含benchmark log)

[2009.1.22新增]感謝softpapa網友提供的資料,從該網頁的兩張比較圖很清楚看到兩個事實,第一個是epoll和kqueue幾乎是壓倒性的勝利贏了select和poll,其二就是像我這樣做樣本數這麼少的試驗意義不大,有時間我會再多測幾遍

測試畫面如下

程式碼列如下

[select]

  1. #include <stdio.h> 
  2. #include <unistd.h> 
  3. #include <sys/socket.h> 
  4. #include <sys/select.h> 
  5. #include <arpa/inet.h> 
  6. #include <netdb.h> 
  7. #include <stdlib.h> 
  8. #include <string.h> 
  9.  
  10. #define WEBMSG "HTTP/1.1 200 OK\r\nContent-Length: 27\r\nConnection: close\r\nContent-Type: text/html\r\n\r\nHello This is select server"
  11.  
  12. int main(int argc,char *argv[]) 
  13. { 
  14. struct sockaddr_in serv,client;
  15. int sockfd,clientfd[FD_SETSIZE],i,width,connfd,n,clientNumber=1,readCount;
  16. fd_set rset,allset;
  17. socklen_t clnlen;
  18. char buffer[1500];
  19.  
  20.  
  21. for (i=0;i<FD_SETSIZE;i++) 
  22. clientfd[i]=-1;
  23.  
  24. memset(&serv,0,sizeof(serv));
  25. serv.sin_family=AF_INET;
  26. serv.sin_addr.s_addr=inet_addr("192.168.15.25");
  27. serv.sin_port=htons(5050);
  28.  
  29. sockfd=socket(AF_INET,SOCK_STREAM,0);
  30. if (sockfd==-1) 
  31. { 
  32. perror("sockfd");
  33. return 0;
  34. } 
  35. if (bind(sockfd,(struct sockaddr *)&serv,sizeof(serv))==-1) 
  36. { 
  37. perror("bind");
  38. return 0;
  39. } 
  40. if (listen(sockfd,1024)==-1) 
  41. { 
  42. perror("listen");
  43. return 0;
  44. } 
  45. FD_ZERO(&allset);
  46. FD_SET(sockfd,&allset);
  47. width=sockfd;
  48.  
  49. while (1) 
  50. { 
  51. clnlen=sizeof(client);
  52. rset=allset;
  53.  
  54. n=select(width+1,&rset,NULL,NULL,NULL);
  55. if (n<=0) continue;
  56.  
  57. if (FD_ISSET(sockfd,&rset)) 
  58. { 
  59. connfd=accept(sockfd,(struct sockaddr *)&client,&clnlen);
  60. printf("connfd :%d\n",connfd);
  61. for (i=0;i<FD_SETSIZE;i++) 
  62. { 
  63. if (clientfd[i]==-1) 
  64. { 
  65. clientfd[i]=connfd;
  66. FD_SET(connfd,&allset);
  67. if (clientNumber<(i+1)) clientNumber=i+1;
  68. break;
  69. } 
  70. } 
  71. if (connfd>width) width=connfd;
  72.  
  73. } 
  74. for (i=0;i<clientNumber;i++) 
  75. { 
  76. if (clientfd[i]!=-1) 
  77. { 
  78. if (FD_ISSET(clientfd[i],&rset)) 
  79. { 
  80. readCount=read(clientfd[i],buffer,1500);
  81. printf("buffer %s\n",buffer);
  82. printf("write msg to client\n");
  83. write(clientfd[i],WEBMSG,strlen(WEBMSG));
  84. close(clientfd[i]);
  85. FD_CLR(clientfd[i],&allset);
  86. clientfd[i]=-1;
  87. } 
  88. } 
  89. } 
  90. } 
  91. }

[poll]

  1. #include <stdio.h> 
  2. #include <unistd.h> 
  3. #include <sys/socket.h> 
  4. #include <sys/poll.h> 
  5. #include <arpa/inet.h> 
  6. #include <netdb.h> 
  7. #include <stdlib.h> 
  8. #include <string.h> 
  9.  
  10. #define WEBMSG "HTTP/1.1 200 OK\r\nContent-Length: 25\r\nConnection: close\r\nContent-Type: text/html\r\n\r\nHello This is poll server"
  11.  
  12. int main(int argc,char *argv[]) 
  13. { 
  14. struct sockaddr_in serv,client;
  15. int sockfd,i,connfd,n,clientNumber=1,readCount;
  16. socklen_t clnlen;
  17. char buffer[1500];
  18. struct pollfd fds[FD_SETSIZE];
  19.  
  20.  
  21. for (i=0;i<FD_SETSIZE;i++) 
  22. fds[i].fd=-1;
  23.  
  24. memset(&serv,0,sizeof(serv));
  25. serv.sin_family=AF_INET;
  26. serv.sin_addr.s_addr=inet_addr("192.168.15.25");
  27. serv.sin_port=htons(5050);
  28.  
  29. sockfd=socket(AF_INET,SOCK_STREAM,0);
  30. if (sockfd==-1) 
  31. { 
  32. perror("sockfd");
  33. return 0;
  34. } 
  35. if (bind(sockfd,(struct sockaddr *)&serv,sizeof(serv))==-1) 
  36. { 
  37. perror("bind");
  38. return 0;
  39. } 
  40. if (listen(sockfd,1024)==-1) 
  41. { 
  42. perror("listen");
  43. return 0;
  44. } 
  45. fds[0].fd=sockfd;
  46. fds[0].events=POLLIN|POLLOUT;
  47.  
  48. while (1) 
  49. { 
  50. clnlen=sizeof(client);
  51.  
  52. n=poll(fds,FD_SETSIZE,5000);
  53. if (n<=0) continue;
  54.  
  55. if (fds[0].revents & POLLIN) 
  56. { 
  57. connfd=accept(sockfd,(struct sockaddr *)&client,&clnlen);
  58. printf("connfd :%d\n",connfd);
  59. for (i=1;i<FD_SETSIZE;i++) 
  60. { 
  61. if (fds[i].fd==-1) 
  62. { 
  63. fds[i].fd=connfd;
  64. fds[i].events=POLLIN|POLLOUT;
  65. if (clientNumber<=i) clientNumber=i;
  66. break;
  67. } 
  68. } 
  69. } 
  70. for (i=1;i<=clientNumber;i++) 
  71. { 
  72. if (fds[i].fd!=-1) 
  73. { 
  74. if (fds[i].revents & POLLIN) 
  75. { 
  76. readCount=read(fds[i].fd,buffer,1500);
  77. printf("buffer %s\n",buffer);
  78. if (fds[i].revents & POLLOUT) 
  79. { 
  80. printf("write msg to client\n");
  81. write(fds[i].fd,WEBMSG,strlen(WEBMSG));
  82. close(fds[i].fd);
  83. fds[i].fd=-1;
  84. } 
  85. } 
  86.  
  87. } 
  88. } 
  89. } 
  90. }

[epoll]

  1. #include <sys/epoll.h> 
  2. #include <stdio.h> 
  3. #include <unistd.h> 
  4. #include <sys/socket.h> 
  5. #include <arpa/inet.h> 
  6. #include <netdb.h> 
  7. #include <stdlib.h> 
  8. #include <string.h> 
  9. #define WEBMSG "HTTP/1.1 200 OK\r\nContent-Length: 26\r\nConnection: close\r\nContent-Type: text/html\r\n\r\nHello This is epoll server"
  10. int main(int argc,char *argv[]) 
  11. { 
  12. struct sockaddr_in serv,client;
  13. int sockfd,i,connfd,n,clientNumber=1,readCount,delfd;
  14. socklen_t clnlen;
  15. char buffer[1500];
  16. int epfd;
  17. struct epoll_event ev,events[FD_SETSIZE];
  18.  
  19. epfd=epoll_create(FD_SETSIZE);
  20. memset(&serv,0,sizeof(serv));
  21. serv.sin_family=AF_INET;
  22. serv.sin_addr.s_addr=inet_addr("192.168.15.25");
  23. serv.sin_port=htons(5050);
  24.  
  25. sockfd=socket(AF_INET,SOCK_STREAM,0);
  26. if (sockfd==-1) 
  27. { 
  28. perror("sockfd");
  29. return 0;
  30. } 
  31. if (bind(sockfd,(struct sockaddr *)&serv,sizeof(serv))==-1) 
  32. { 
  33. perror("bind");
  34. return 0;
  35. } 
  36. if (listen(sockfd,1024)==-1) 
  37. { 
  38. perror("listen");
  39. return 0;
  40. } 
  41.  
  42. ev.data.fd = sockfd;
  43. ev.events = EPOLLIN | EPOLLET;
  44. epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &ev);
  45.  
  46. while (1) 
  47. { 
  48. clnlen=sizeof(client);
  49. n=epoll_wait(epfd, events, FD_SETSIZE , -1);
  50. if (n<=0) continue;
  51. for (i=0;i<=n;i++) 
  52. { 
  53. if (events[i].events & EPOLLIN && events[i].data.fd==sockfd) 
  54. { 
  55. connfd=accept(sockfd,(struct sockaddr *)&client,&clnlen);
  56. printf("connfd :%d\n",connfd);
  57. ev.data.fd = connfd;
  58. ev.events = EPOLLIN |EPOLLET|EPOLLOUT ;
  59. epoll_ctl(epfd, EPOLL_CTL_ADD, connfd, &ev);
  60. } 
  61. if (events[i].events & EPOLLIN && events[i].data.fd!=sockfd) 
  62. { 
  63. readCount=read(events[i].data.fd,buffer,1500);
  64. printf("buffer %s\n",buffer);
  65. if (events[i].events & EPOLLOUT) 
  66. { 
  67. printf("write msg to client\n");
  68. write(events[i].data.fd,WEBMSG,strlen(WEBMSG));
  69. delfd=events[i].data.fd;
  70. ev.data.fd=delfd;
  71. epoll_ctl(epfd, EPOLL_CTL_DEL, delfd, &ev);
  72. close(delfd);
  73. } 
  74. } 
  75. } 
  76. } 
  77. }

標籤: linux
評論: 2 | 引用: 0 | 閱讀: 18914
  • 1 
softpapa [ 2009-01-22 00:19 網址 | 回覆 | 編輯 刪除 ]
http://monkey.org/~provos/libevent/ 有兩張圖可以參考一下...:P
Joey [ 回復於2009-01-22 09:07 郵箱 | 編輯 刪除 ]
非常感謝,已新增內容於此篇網誌,找時間想try libevent....
  • 1 
發表評論
暱 稱: 密 碼:
網 址: E - mail:
驗證碼: 驗證碼圖片 選 項:
頭 像:
內 容: