有天在看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]
- #include <stdio.h>
- #include <unistd.h>
- #include <sys/socket.h>
- #include <sys/select.h>
- #include <arpa/inet.h>
- #include <netdb.h>
- #include <stdlib.h>
- #include <string.h>
-
- #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"
-
- int main(int argc,char *argv[])
- {
- struct sockaddr_in serv,client;
- int sockfd,clientfd[FD_SETSIZE],i,width,connfd,n,clientNumber=1,readCount;
- fd_set rset,allset;
- socklen_t clnlen;
- char buffer[1500];
-
-
- for (i=0;i<FD_SETSIZE;i++)
- clientfd[i]=-1;
-
- memset(&serv,0,sizeof(serv));
- serv.sin_family=AF_INET;
- serv.sin_addr.s_addr=inet_addr("192.168.15.25");
- serv.sin_port=htons(5050);
-
- sockfd=socket(AF_INET,SOCK_STREAM,0);
- if (sockfd==-1)
- {
- perror("sockfd");
- return 0;
- }
- if (bind(sockfd,(struct sockaddr *)&serv,sizeof(serv))==-1)
- {
- perror("bind");
- return 0;
- }
- if (listen(sockfd,1024)==-1)
- {
- perror("listen");
- return 0;
- }
- FD_ZERO(&allset);
- FD_SET(sockfd,&allset);
- width=sockfd;
-
- while (1)
- {
- clnlen=sizeof(client);
- rset=allset;
-
- n=select(width+1,&rset,NULL,NULL,NULL);
- if (n<=0) continue;
-
- if (FD_ISSET(sockfd,&rset))
- {
- connfd=accept(sockfd,(struct sockaddr *)&client,&clnlen);
- printf("connfd :%d\n",connfd);
- for (i=0;i<FD_SETSIZE;i++)
- {
- if (clientfd[i]==-1)
- {
- clientfd[i]=connfd;
- FD_SET(connfd,&allset);
- if (clientNumber<(i+1)) clientNumber=i+1;
- break;
- }
- }
- if (connfd>width) width=connfd;
-
- }
- for (i=0;i<clientNumber;i++)
- {
- if (clientfd[i]!=-1)
- {
- if (FD_ISSET(clientfd[i],&rset))
- {
- readCount=read(clientfd[i],buffer,1500);
- printf("buffer %s\n",buffer);
- printf("write msg to client\n");
- write(clientfd[i],WEBMSG,strlen(WEBMSG));
- close(clientfd[i]);
- FD_CLR(clientfd[i],&allset);
- clientfd[i]=-1;
- }
- }
- }
- }
- }
[poll]
- #include <stdio.h>
- #include <unistd.h>
- #include <sys/socket.h>
- #include <sys/poll.h>
- #include <arpa/inet.h>
- #include <netdb.h>
- #include <stdlib.h>
- #include <string.h>
-
- #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"
-
- int main(int argc,char *argv[])
- {
- struct sockaddr_in serv,client;
- int sockfd,i,connfd,n,clientNumber=1,readCount;
- socklen_t clnlen;
- char buffer[1500];
- struct pollfd fds[FD_SETSIZE];
-
-
- for (i=0;i<FD_SETSIZE;i++)
- fds[i].fd=-1;
-
- memset(&serv,0,sizeof(serv));
- serv.sin_family=AF_INET;
- serv.sin_addr.s_addr=inet_addr("192.168.15.25");
- serv.sin_port=htons(5050);
-
- sockfd=socket(AF_INET,SOCK_STREAM,0);
- if (sockfd==-1)
- {
- perror("sockfd");
- return 0;
- }
- if (bind(sockfd,(struct sockaddr *)&serv,sizeof(serv))==-1)
- {
- perror("bind");
- return 0;
- }
- if (listen(sockfd,1024)==-1)
- {
- perror("listen");
- return 0;
- }
- fds[0].fd=sockfd;
- fds[0].events=POLLIN|POLLOUT;
-
- while (1)
- {
- clnlen=sizeof(client);
-
- n=poll(fds,FD_SETSIZE,5000);
- if (n<=0) continue;
-
- if (fds[0].revents & POLLIN)
- {
- connfd=accept(sockfd,(struct sockaddr *)&client,&clnlen);
- printf("connfd :%d\n",connfd);
- for (i=1;i<FD_SETSIZE;i++)
- {
- if (fds[i].fd==-1)
- {
- fds[i].fd=connfd;
- fds[i].events=POLLIN|POLLOUT;
- if (clientNumber<=i) clientNumber=i;
- break;
- }
- }
- }
- for (i=1;i<=clientNumber;i++)
- {
- if (fds[i].fd!=-1)
- {
- if (fds[i].revents & POLLIN)
- {
- readCount=read(fds[i].fd,buffer,1500);
- printf("buffer %s\n",buffer);
- if (fds[i].revents & POLLOUT)
- {
- printf("write msg to client\n");
- write(fds[i].fd,WEBMSG,strlen(WEBMSG));
- close(fds[i].fd);
- fds[i].fd=-1;
- }
- }
-
- }
- }
- }
- }
[epoll]
- #include <sys/epoll.h>
- #include <stdio.h>
- #include <unistd.h>
- #include <sys/socket.h>
- #include <arpa/inet.h>
- #include <netdb.h>
- #include <stdlib.h>
- #include <string.h>
- #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"
- int main(int argc,char *argv[])
- {
- struct sockaddr_in serv,client;
- int sockfd,i,connfd,n,clientNumber=1,readCount,delfd;
- socklen_t clnlen;
- char buffer[1500];
- int epfd;
- struct epoll_event ev,events[FD_SETSIZE];
-
- epfd=epoll_create(FD_SETSIZE);
- memset(&serv,0,sizeof(serv));
- serv.sin_family=AF_INET;
- serv.sin_addr.s_addr=inet_addr("192.168.15.25");
- serv.sin_port=htons(5050);
-
- sockfd=socket(AF_INET,SOCK_STREAM,0);
- if (sockfd==-1)
- {
- perror("sockfd");
- return 0;
- }
- if (bind(sockfd,(struct sockaddr *)&serv,sizeof(serv))==-1)
- {
- perror("bind");
- return 0;
- }
- if (listen(sockfd,1024)==-1)
- {
- perror("listen");
- return 0;
- }
-
- ev.data.fd = sockfd;
- ev.events = EPOLLIN | EPOLLET;
- epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &ev);
-
- while (1)
- {
- clnlen=sizeof(client);
- n=epoll_wait(epfd, events, FD_SETSIZE , -1);
- if (n<=0) continue;
- for (i=0;i<=n;i++)
- {
- if (events[i].events & EPOLLIN && events[i].data.fd==sockfd)
- {
- connfd=accept(sockfd,(struct sockaddr *)&client,&clnlen);
- printf("connfd :%d\n",connfd);
- ev.data.fd = connfd;
- ev.events = EPOLLIN |EPOLLET|EPOLLOUT ;
- epoll_ctl(epfd, EPOLL_CTL_ADD, connfd, &ev);
- }
- if (events[i].events & EPOLLIN && events[i].data.fd!=sockfd)
- {
- readCount=read(events[i].data.fd,buffer,1500);
- printf("buffer %s\n",buffer);
- if (events[i].events & EPOLLOUT)
- {
- printf("write msg to client\n");
- write(events[i].data.fd,WEBMSG,strlen(WEBMSG));
- delfd=events[i].data.fd;
- ev.data.fd=delfd;
- epoll_ctl(epfd, EPOLL_CTL_DEL, delfd, &ev);
- close(delfd);
- }
- }
- }
- }
- }
Regular expression-跟brainfuck差不多的東西 (2009-11-13 15:37)
Reading file in kernel-簡單但實用 (2009-10-13 15:18)
Linux file system for dummies-只花你45分鐘 (2009-08-19 15:40)
OPENSSL-TCP SSL初心者之路 (2009-07-16 15:16)
NAPI與pure interrupt driver的效能比較 (2009-04-29 19:06)
usermode helper-來自kernel的呼喚 (2009-04-21 16:19)
kernel module memory detector-抓出有害的kernel module (2009-03-31 13:50)
kernel space coding-如履薄冰 (2009-03-26 09:52)
readahead與posix_advise-預讀取是萬能靈丹? (2009-03-06 15:54)