accept驚群研究

2021-08-15 08:12:34 字數 3135 閱讀 8186

一:驚群的定義

驚群是多程序多執行緒程式設計中的乙個常見問題,就是當多個程序和執行緒在同時阻塞等待同乙個事件時,如果這個事件發生,會喚醒所有的程序,但最終只可能有乙個程序/執行緒對該事件進行處理,其他程序/執行緒會在失敗後重新休眠,這種效能浪費就是驚群。

二:accept驚群

在使用多程序處理客戶端-伺服器連線時,往往會出現驚群現象,即在主程序listen之後呼叫fork建立多個子程序之後,這些子程序由於等待客戶端的connect鏈結而處於睡眠狀態,而每次只有乙個鏈結進入,核心會所有的子程序來處理,往往只有乙個程序能夠獲得鏈結,而且他的子程序又要重新回到睡眠狀態。

以前舊版本的linux沒有解決accept驚群,目前的linux已經解決了accept驚群。下面展示實驗部分內容。

server.c檔案如下所示:

#include

#include

#include

#include

#include

#include

#define process_num 3  

int main()  

}  }  int status;  

wait(&status);  

return 0;  

}為了簡單起見,主程序只建立兩三個子程序,共三個子程序來處理客戶端鏈結。

client.c檔案如下所示:

#include

#include

#include

#include

#include

#include

#include

int main(int argc, char *argv)  

if( argc > 2 )      //函式傳參,可以更改伺服器的埠號                                     

int sockfd;  

sockfd = socket(af_inet, sock_stream, 0);// 建立通訊端點:套接字  

if(sockfd < 0)  

// 設定伺服器位址結構體  

struct sockaddr_in server_addr;  

bzero(&server_addr,sizeof(server_addr)); // 初始化伺服器位址  

server_addr.sin_family = af_inet;   // ipv4  

server_addr.sin_port = htons(port); // 埠  

inet_pton(af_inet, server_ip, &server_addr.sin_addr.s_addr);    // ip  

// 主動連線伺服器  

int err_log = connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr));       

if(err_log != 0)  

char send_buf[512] = ;  

printf("send data to %s:%d\n",server_ip,port);  

while(1)  

close(sockfd);  

return 0;  

}接下來編譯執行server,然後使用ps –ef|grep ./server觀察

jack      4341  4340  0 05:36 pts/6    00:00:00 ./server

jack      4342  4340  0 05:36 pts/6    00:00:00 ./server

jack      4343  4340  0 05:36 pts/6    00:00:00 ./server

接下來觀察 /proc/[pid]/status目錄下的內容結果如下所示:

pidvoluntary_ctxt_switches

nonvoluntary_ctxt_switches

43411 0

43421 0

43431 0

其中voluntary_ctxt_switches 代表主動放棄cpu的次數,nonvoluntary_ctxt_switches: 代表被動放棄cpu的次數,接著執行./client,在./server終端中出現process 4341 accept success!然後重新觀察/proc/[pid]/status目錄,結果如下:

pidvoluntary_ctxt_switches

nonvoluntary_ctxt_switches

43412 0

43421 0

43431 0

結果表明只有4341號程序獲得了一次cpu,並且處理了connect之後又主動放棄了cpu,其餘子程序仍然處於睡眠狀態,並未發生上下文切換。

目前核心解決了accept的驚群問題,並未解決epoll驚群,該部落格**有epoll驚群原始碼,和為何不解決epoll驚群的原因。大家可以按照上述方法去驗證一下epoll驚群。

三 核心如何解決accept驚群

因為涉及到核心,水平有限,不能進行實驗驗證。只能從原理上大概分析一下。

通常情況下,我們首先能想到的就是進行加鎖操作,這樣一來,獲得鎖的程序阻塞與accept呼叫,而未獲得鎖的程序阻塞於鎖的獲取。這樣可以有一定的效能提高,但是當unlock(),釋放鎖之後,同樣會面臨鎖的爭搶,也會出現驚群現象。

核心開發者增加了乙個「互斥等待」選項。乙個互斥等待的行為與睡眠基本類似,主要的不同點在於:

1)當乙個等待佇列入口有 wq_flag_excluseve 標誌置位, 它被新增到等待佇列的尾部. 沒有這個標誌的入口項, 相反, 新增到開始.

2)當 wake_up 被在乙個等待佇列上呼叫時, 它在喚醒第乙個有 wq_flag_exclusive 標誌的程序後停止。

也就是說,對於互斥等待的行為,比如如對乙個listen後的socket描述符,多執行緒阻塞accept時,系統核心只會喚醒所有正在等待此時間的佇列 的第乙個,佇列中的其他人則繼續等待下一次事件的發生,這樣就避免的多個執行緒同時監聽同乙個socket描述符時的驚群問題。

其實驚群的根本原因在於資源競爭,假如核心可以將資源競爭改為資源分配,這樣核心就有了主動權,驚群問題就可以得到緩解。一般的設計可以在父程序中進行accept呼叫,然後將已連線套接字傳遞給某個子程序。

accpet驚群和epoll驚群現象

epoll的驚群現象解決。想一想nginx解決的應該時epoll的驚群問題具體 網上有就不貼出。得到鎖的可以將accpet放進自己的epoll中然後。沒有得到的移出去 在思考這個問題之前,我們應該以前對前面所講幾點有所了解,即先弄清楚問題的背景,並能自己復現出來,而不僅僅只是看書或部落格,然後再來看...

epoll 群驚現象

遇到問題 手頭原來有乙個單程序的linux epoll伺服器程式,近來希望將它改寫成多程序版本,主要原因有 在服務高峰期間 併發的 網路請求非常海量,目前的單程序版本的程式有點吃不消 單程序時只有乙個迴圈先後處理epoll wait 到的事件,使得某些不幸排隊靠後的socket fd的事件處理不及時...

epoll驚群測試

3.1.1 核心版本3.10測試結果 兩個程序均被喚醒 3.1.2 核心版本4.18測試結果 僅有乙個程序被喚醒。如果在epoll wait之後sleep一秒,結果如下 兩個程序均被喚醒,總共收到乙個包。小結 較新版本的核心做了一些優化,不一定會喚醒所有的程序。核心版本為3.10和4.18結果一致,...