惊群效应:
1、上下文切换(context switch)过高会导致cpu像个搬运工,频繁地在寄存器和运行队列之间奔波,更多的时间花在了进程(线程)切换,而不是在真正工作的进程(线程)上面。直接的消耗包括cpu寄存器要保存和加载(例如程序计数器)、系统调度器的代码需要执行。间接的消耗在于多核cache之间的共享数据。
2、通过锁机制解决惊群效应是一种方法,在任意时刻只让一个进程(线程)处理等待的事件。但是锁机制也会造成cpu等资源的消耗和性能损耗
1 #include<stdio.h> 2 #include<sys/types.h> 3 #include<sys/socket.h> 4 #include<unistd.h> 5 #include<sys/epoll.h> 6 #include<netdb.h> 7 #include<stdlib.h> 8 #include<fcntl.h> 9 #include<sys/wait.h> 10 #include<errno.h> 11 #define PROCESS_NUM 10 12 #define MAXEVENTS 64 13 //socket创建和绑定 14 int sock_creat_bind(char * port){ 15 int sock_fd = socket(AF_INET, SOCK_STREAM, 0); 16 struct sockaddr_in serveraddr; 17 serveraddr.sin_family = AF_INET; 18 serveraddr.sin_port = htons(atoi(port)); 19 serveraddr.sin_addr.s_addr = htonl(INADDR_ANY); 20 21 bind(sock_fd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)); 22 return sock_fd; 23 } 24 //利用fcntl设置文件或者函数调用的状态标志 25 int make_nonblocking(int fd){ 26 int val = fcntl(fd, F_GETFL); 27 val |= O_NONBLOCK; 28 if(fcntl(fd, F_SETFL, val) < 0){ 29 perror("fcntl set"); 30 return -1; 31 } 32 return 0; 33 } 34 35 int main(int argc, char *argv[]) 36 { 37 int sock_fd, epoll_fd; 38 struct epoll_event event; 39 struct epoll_event *events; 40 41 if(argc < 2){ 42 printf("usage: [port] %s", argv[1]); 43 exit(1); 44 } 45 if((sock_fd = sock_creat_bind(argv[1])) < 0){ 46 perror("socket and bind"); 47 exit(1); 48 } 49 if(make_nonblocking(sock_fd) < 0){ 50 perror("make non blocking"); 51 exit(1); 52 } 53 if(listen(sock_fd, SOMAXCONN) < 0){ 54 perror("listen"); 55 exit(1); 56 } 57 if((epoll_fd = epoll_create(MAXEVENTS))< 0){ 58 perror("epoll_create"); 59 exit(1); 60 } 61 event.data.fd = sock_fd; 62 event.events = EPOLLIN; 63 if(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, sock_fd, &event) < 0){ 64 perror("epoll_ctl"); 65 exit(1); 66 } 67 /*buffer where events are returned*/ 68 events = calloc(MAXEVENTS, sizeof(event)); 69 int i; 70 for(i = 0; i < PROCESS_NUM; ++i){ 71 int pid = fork(); 72 if(pid == 0){ 73 while(1){ 74 int num, j; 75 num = epoll_wait(epoll_fd, events, MAXEVENTS, -1); 76 printf("process %d returnt from epoll_wait ", getpid()); 77 sleep(2); 78 for(i = 0; i < num; ++i){ 79 if((events[i].events & EPOLLERR) || (events[i].events & EPOLLHUP) || (!(events[i].events & EPOLLIN))){ 80 fprintf(stderr, "epoll error "); 81 close(events[i].data.fd); 82 continue; 83 }else if(sock_fd == events[i].data.fd){ 84 //收到关于监听套接字的通知,意味着一盒或者多个传入连接 85 struct sockaddr in_addr; 86 socklen_t in_len = sizeof(in_addr); 87 if(accept(sock_fd, &in_addr, &in_len) < 0){ 88 printf("process %d accept failed! ", getpid()); 89 }else{ 90 printf("process %d accept successful! ", getpid()); 91 } 92 } 93 } 94 } 95 } 96 } 97 wait(0); 98 free(events); 99 close(sock_fd); 100 return 0; 101 }
fly@G480:~/fly/learn/test$ strace -f ./fork
execve("./fork", ["./fork"], 0x7fffd0d489d8 /* 61 vars */) = 0
brk(NULL) = 0x55e33c728000
arch_prctl(0x3001 /* ARCH_??? */, 0x7fff1f212060) = -1 EINVAL (Invalid argument)
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=102598, ...}) = 0
mmap(NULL, 102598, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f29c9075000
close(3) = 0
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "177ELF2113 3 >