程序池模型需要通過system v ipc機制或管道、訊號、檔案鎖等進行同步。以下是程序池的一般模型。
linux驚群現象:
驚群:驚群是指多個程序/執行緒在等待同一資源時,每當資源可用,所有的程序/執行緒都來競爭資源的現象。
accept、select、epoll實現程序池模型時的驚群現象:
1).linux多程序accept系統呼叫的驚群問題(注意,這裡沒有使用select、epoll等事件機制),在linux 2.6版本之前的版本存在,在之後的版本中解決掉了。
2).使用select epoll等事件機制,在linux早期的版本中,驚群問題依然存在(epoll_create在fork之前)。 原因與之前單純使用accept導致驚群,原因類似。epoll的驚群問題,同樣在之後的某個版本部分解決了。
3).epoll_create在fork之後呼叫,不能避免驚群問題,nginx使用互斥鎖,解決epoll驚群問題。
程序池中的程序呼叫accept如果阻塞在同乙個listen佇列中,有可能產生驚群現象(取決於linux版本):當一connect到達時,所有accept都會喚醒,但只有乙個accept會返回正確結果,其他的都會返回錯誤碼。
accept多程序實現:讓乙個程序bind乙個網路位址(可能是af_inet,af_unix或者其他任何你想要的),然後fork這個程序自己:
int s = socket(...)
bind(s, ...)
listen(s, ...)
fork()
fork自己幾次之後,每個程序阻塞在accept()函式這裡
在較老的unix系統中,當有連線到來時,accept()在每個阻塞在這的程序裡被喚醒。但是,只有這些程序中的乙個能夠真正的accept這個連線,其他的程序accept將返回eagain驚群造成結果是系統對使用者程序/執行緒頻繁的做無效的排程、上下文切換,系統系能大打折扣。
實現**:
伺服器端**:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define buflen 1024
#define pidnum 3
/*******************併發伺服器模型之一:預先分配好了程序的個數**********************/
static void handle_fork(int sockfd)else
printf("\n*****************通訊開始***************\n");
printf("正在與您通訊的客戶端是:%s: %d\n",inet_ntoa(c_addr.sin_addr),ntohs(c_addr.sin_port));
/******處理客戶端請求*******/
bzero(buf,buflen);
len = recv(newfd,buf,buflen,0);
if(len >0 && !strncmp(buf,"time",4))
/*關閉通訊的套接字*/
close(newfd);}}
int main(int argc, char **ar**)
else
printf("socket create success!\n");
/*設定伺服器端口*/
if(ar**[2])
port = atoi(ar**[2]);
else
port = 4567;
/*設定偵聽佇列長度*/
if(ar**[3])
listnum = atoi(ar**[3]);
else
listnum = 3;
/*設定伺服器ip*/
bzero(&s_addr, sizeof(s_addr));
s_addr.sin_family = af_inet;
s_addr.sin_port = htons(port);
if(ar**[1])
s_addr.sin_addr.s_addr = inet_addr(ar**[1]);
else
s_addr.sin_addr.s_addr = inaddr_any;
/*把位址和埠幫定到套接字上*/
if((bind(sockfd, (struct sockaddr*) &s_addr,sizeof(struct sockaddr))) == -1)else
printf("bind success!\n");
/*偵聽本地埠*/
if(listen(sockfd,listnum) == -1)else
printf("the server is listening!\n");
/*處理客戶端的連線*/
int i = 0;
for(i = 0; i < pidnum; i++)
/*關閉伺服器的套接字*/
close(sockfd);
return 0;
}客戶端**:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define buflen 1024
int main(int argc, char **ar**)
else
printf("socket create success!\n");
/*設定伺服器端口*/
if(ar**[2])
port = atoi(ar**[2]);
else
port = 4567;
/*設定伺服器ip*/
bzero(&s_addr, sizeof(s_addr));
s_addr.sin_family = af_inet;
s_addr.sin_port = htons(port);
if (inet_aton(ar**[1], (struct in_addr *)&s_addr.sin_addr.s_addr) == 0)
/*開始連線伺服器*/
if(connect(sockfd,(struct sockaddr*)&s_addr,sizeof(struct sockaddr)) == -1)else
printf("conncet success!\n");
/******緩衝區清零*******/
bzero(buf,buflen);
strcpy(buf,"time");
/******傳送訊息*******/
send(sockfd,buf,strlen(buf),0);
/******緩衝區清零*******/
bzero(buf,buflen);
/******接收訊息*******/
len = recv(sockfd,buf,buflen,0);
if(len > 0)
printf("伺服器的系統時間是:%s\n",buf);
close(sockfd); /*關閉連線*/
return 0;
}
程序池 執行緒池
程序池和執行緒池相似,所以這裡我們以程序池為例介紹,下面對程序池的討論完全適用於執行緒池 如果沒有特殊宣告 程序池是由伺服器預先建立的一組子程序,這些子程序的數目在3 10個之間 典型情況 執行緒池的數量應該和cpu數量差不多。程序池中的所有子程序都執行者相同的 並具有相同的屬性。因為程序池在伺服器...
執行緒池 程序池
執行緒池 程序池 池子解決什麼問題?1.建立 銷毀執行緒伴隨著系統開銷,如果過於頻繁會影響系統執行效率 2.執行緒併發數量過多,搶占系統資源,從而導致系統阻塞甚至宕機 3.能夠剛好的控制和管理池子裡面的執行緒和程序 concurrent.futures模組提供了高度封裝的非同步呼叫介面 thread...
程序池, 執行緒池
知識儲備 池 裝載固定數量介質,該介質值得是程序或者執行緒 為什麼要用?讓機器在自己可承受的範圍內去保證乙個高效的工作 from concurrent.futures import processpoolexecutor,threadpoolexecutor pool processpoolexec...