免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 5762 | 回复: 17
打印 上一主题 下一主题

[C] epoll+线程池web 测试结果。 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2013-02-21 11:50 |只看该作者 |倒序浏览
本帖最后由 bio_tt 于 2013-02-21 15:50 编辑

用epoll+拥有10个线程的线程池,作为web server,用ab 测试了一下

结果如下:

ab -c 1000 -t 5  *************:9000/
This is ApacheBench, Version 2.0.41-dev <$Revision: 1.141 $> apache-2.0
Copyright (c) 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Copyright (c) 1998-2002 The Apache Software Foundation, http://www.apache.org/

Benchmarking ******************* (be patient)
Completed 5000 requests
Completed 10000 requests
Finished 12995 requests


Server Software:
Server Hostname:        **************
Server Port:            9000

Document Path:          /
Document Length:        6888 bytes

Concurrency Level:      1000
Time taken for tests:   5.479 seconds
Complete requests:      12995
Failed requests:        0
Write errors:           0
Total transferred:      90095204 bytes
HTML transferred:       89523336 bytes
Requests per second:    2598.75 [#/sec] (mean)
Time per request:       384.800 [ms] (mean)
Time per request:       0.385 [ms] (mean, across all concurrent requests)
Transfer rate:          17594.91 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0  132 598.6      4    3006
Processing:     1   38  26.3     31     290
Waiting:        0   26  23.2     21     280
Total:          2  171 606.5     35    3290

Percentage of the requests served within a certain time (ms)
  50%     35
  66%     41
  75%     47
  80%     54
  90%    127
  95%    203
  98%   3072
  99%   3095
100%   3290 (longest request)


感觉还是不够快。。


用strace跟踪了一下。

strace  -c -p 12891
Process 12891 attached - interrupt to quit
Process 12891 detached
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
68.45    1.469389          44     33654      2897 futex
11.89    0.255126          10     26142           epoll_ctl
10.99    0.236004          18     13297       226 accept
  5.43    0.116617         223       524           epoll_wait
  3.24    0.069480           5     13071           fcntl
------ ----------- ----------- --------- --------- ----------------
100.00    2.146616                 86688      3123 total

发现时间主要耗在 futex上。。70%了。。就大侠支招改进。。
主要是工作线程间使用了pthread_mutex_lock.


贴点代码:

struct data{
int fd;
struct data *next;
};
struct data *all,*main1;
int epfd;
struct epoll_event ev;
pthread_mutex_t lock=PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t flag=PTHREAD_COND_INITIALIZER;

void setnonblocking(int sock)
{
  if(fcntl(sock,F_SETFL,O_NONBLOCK)<0)
   {
     printf("fcntl set error1\n";exit(1);
   }
}

void do_work()
{
while(1)
{
  int check_all=0;
  int client_sockfd;
  pthread_mutex_lock(&lock);
  while(all == NULL)
   {
    pthread_cond_wait(&flag,&lock);
   }
  struct data *tmp1=all;
  client_sockfd=tmp1->fd;
  all=tmp1->next;
  free(tmp1);
  int flaga;
  flaga=fcntl(client_sockfd,F_GETFL,0);
  flaga &=~O_NONBLOCK;
  if(fcntl(client_sockfd,F_SETFL,flaga) == -1)
        perror("fcntl";
   pthread_mutex_unlock(&lock);
  读,然后发数据
}
}

void main(int argc,char *argv[])
{
  daemon();
  struct sigaction sa;
  sa.sa_handler=SIG_IGN;
  sigaction(SIGPIPE,&sa,0);
  int len,nfds,opts,listenfd,client,sockfd;
  struct sockaddr_in server_addr,client_addr;
  struct epoll_event events[1000];
  listenfd=socket(AF_INET,SOCK_STREAM,0);
  setnonblocking(listenfd);
  bzero(&server_addr,sizeof(server_addr));
  server_addr.sin_family=AF_INET;
  server_addr.sin_port=htons(9000);
  server_addr.sin_addr.s_addr=inet_addr("114.255.218.163";
  setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,1,sizeof(int));
  int nRecvBuf=32*1024;
  setsockopt(listenfd,SOL_SOCKET,SO_RCVBUF,(const char*)&nRecvBuf,sizeof(int));
  bind(listenfd,(struct sockaddr *)&server_addr,sizeof(server_addr));
  listen(listenfd,50);
  epfd=epoll_create(10000);
  ev.data.fd=listenfd;
  ev.events=EPOLLIN|EPOLLET;
  epoll_ctl(epfd,EPOLL_CTL_ADD,listenfd,&ev);

  int i,maxi=0;
  pthread_t go[10];
  for(i=0;i<10;i++)
   {
      pthread_create(&go,NULL,(void *)do_work,NULL);
      pthread_detach(go);
   }
    for(;
     {
        nfds=epoll_wait(epfd,events,1000,500);
        for(i=0;i<nfds;i++)
         {
            if(events.data.fd == listenfd)
              {
                 socklen_t client_size=sizeof(client_addr);
                 while(1)
                 {
                   client=accept(listenfd,(struct sockaddr *)&client_addr,&client_size);
                   if(client <0)
                     {
                       break;
                     }
                   setnonblocking(client);

                   ev.data.fd=client;
                   epoll_ctl(epfd,EPOLL_CTL_ADD,client,&ev);
                 }
               }
             else{
                    if(events.events == EPOLLERR)
                       {
                          int readsock=events.data.fd;
                          ev.data.fd=readsock;
                          epoll_ctl(epfd,EPOLL_CTL_DEL,readsock,&ev);
                          close(readsock);
                       }
                     if(events.events == EPOLLIN)
                      {
                          int readsock=events.data.fd;
                          pthread_mutex_lock(&lock);
                          main1=(struct data *)malloc(sizeof(struct data));
                          if(main1 == NULL)
                            {
                                 printf("main1 can not malloc\n";exit(1);
                            }
                          main1->fd=readsock;
                          main1->next=NULL;
                          if(all == NULL)
                          all=main1;
                          else{
                                 struct data *tmp1;
                                 tmp1=all;
                                 while(tmp1->next !=NULL)
                                   tmp1=tmp1->next;
                                 tmp1->next=main1;
                               }
                          pthread_cond_signal(&flag);
                          ev.data.fd=readsock;
                          epoll_ctl(epfd,EPOLL_CTL_DEL,readsock,&ev);
                          pthread_mutex_unlock(&lock);
                     }
              }
       }
}
}

论坛徽章:
4
水瓶座
日期:2013-09-06 12:27:30摩羯座
日期:2013-09-28 14:07:46处女座
日期:2013-10-24 14:25:01酉鸡
日期:2014-04-07 11:54:15
2 [报告]
发表于 2013-02-21 12:31 |只看该作者
想法避免掉锁, http没有什么需要共享的东西吧.

论坛徽章:
0
3 [报告]
发表于 2013-02-21 12:45 |只看该作者
回复 2# linux_c_py_php

就是新来的连接的套接字,我存入到一个链表中的,所以工作线程取链表中的套接字,所以有一个加锁和去锁的过程。。不知道除了这种方法,还有啥方法。。 IPC 消息队列?

   

论坛徽章:
4
水瓶座
日期:2013-09-06 12:27:30摩羯座
日期:2013-09-28 14:07:46处女座
日期:2013-10-24 14:25:01酉鸡
日期:2014-04-07 11:54:15
4 [报告]
发表于 2013-02-21 14:17 |只看该作者
bio_tt 发表于 2013-02-21 12:45
回复 2# linux_c_py_php

就是新来的连接的套接字,我存入到一个链表中的,所以工作线程取链表中的套接字 ...


不知道你的程序结构...

是一个监听线程, 一个socket queue, 一堆worker线程吗?

论坛徽章:
0
5 [报告]
发表于 2013-02-21 14:50 |只看该作者
回复 4# linux_c_py_php

对,就是这样的,监听线程拿到新的socket描述符就会放到socket queue中,这里有个加锁去锁过程,同理worker取socket描述符的时候也有个加锁或者去锁过程。

如果换成消息队列,但是消息队列大小有限制,所以不知道效率咋样。。。求支招。。嘿嘿。
   

论坛徽章:
4
水瓶座
日期:2013-09-06 12:27:30摩羯座
日期:2013-09-28 14:07:46处女座
日期:2013-10-24 14:25:01酉鸡
日期:2014-04-07 11:54:15
6 [报告]
发表于 2013-02-21 15:04 |只看该作者
这样肯定慢... 不过apache也就这么实现的, 你机器什么配置, 跑2500也不一定是程序不行.

论坛徽章:
0
7 [报告]
发表于 2013-02-21 15:09 |只看该作者
队列好点,读写锁,用两个锁。竞争会小点,你这样只有1个锁有竞争会大点

论坛徽章:
0
8 [报告]
发表于 2013-02-21 15:39 |只看该作者
回复 6# linux_c_py_php


    Linux IBM-x3950 2.6.9-42.ELlargesmp #1 SMP Wed Jul 12 23:46:39 EDT 2006 x86_64 x86_64 x86_64 GNU/Linux

    Red Hat Enterprise Linux AS release 4 (Nahant Update 4)

    Intel(R) Xeon(TM) CPU 2.50GHz 16核心。。比较老的机器。

论坛徽章:
4
水瓶座
日期:2013-09-06 12:27:30摩羯座
日期:2013-09-28 14:07:46处女座
日期:2013-10-24 14:25:01酉鸡
日期:2014-04-07 11:54:15
9 [报告]
发表于 2013-02-21 15:42 |只看该作者
是多线程共享一个epoll fd? 一个线程一个epoll fd肯定可以降低futex, 主要是你用了个socket queue, 这个queue是可以不用的.

论坛徽章:
0
10 [报告]
发表于 2013-02-21 15:43 |只看该作者
回复 7# ronaldohf

读写锁搞起来太麻烦了。。而且基本都是修改的过程,读很少。工作线程直接取链表头。不知道除了这种处理方式,还有啥比较好的方式呢?


PS:

  工作线程拿到sockfd描述符后,如果用非阻塞socket句柄,写大文件的时候特别麻烦。。。不好处理。。 ,我直接把socket句柄变回阻塞,进行读取的。。不知道影响大不。

   
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP