------select網絡
1 一個誤區不少人認爲它最大能夠監聽1024個,實際上倒是文件描述符的值不能大於等於1024,因此除掉標準輸入、輸出、錯誤輸出,必定少於1024個,若是在以前還打開了其餘文件,那會更少多線程
2 select返回後,通常要輪詢fd_set,發現新鏈接要加上,鏈接斷開要去掉,這個過程必定要這樣作:select以前把fd_set臨時拷貝一份,輪詢中對它的修改只在臨時fd_set上作,輪詢完了,再對這個臨時fd_set select,不然你可能明明有鏈接進來,卻accept不到,這多是由於輪詢中若是直接修改fdset,select的底層就會定位錯亂併發
------pollsocket
性能測試發現,select與poll有類似的調用時間與cpu佔用率,都隨着數據量變大或者鏈接數變大(活動鏈接不變)而變大tcp
鏈接進入時,返回POLLIN,鏈接關閉時返回POLLERR 或者 POLLIN高併發
------epoll性能
正如傳說的那樣,epoll的調用時間與cpu佔用率只會隨數據量變大,而幾乎不受鏈接數影響測試
當鏈接關閉時,會收到EPOLLIN事件spa
在ET模式下,不論是監聽socket仍是鏈接客戶端的socket,在EPOLLIN時,都應該重複read一直到EAGAIN(屢次鏈接進入或者客戶端的屢次send調用都只產生一次EPOLL事件),不然下次等待EPOLLIN將會掛起,這樣對上層應用處理起來更復雜.net
因此仍是推薦用默認的LT模式
在對客戶端的發送也可能出現阻塞,因此epoll也應該註冊EPOLLOUT,但不是在一開始(那會讓全部文件描述符都返回可用,下降epoll的效率,合理的機制應該是這樣:對accecpt的客戶端鏈接一開始只註冊EPOLLIN事件,觸發後接收客戶端消息,生成回覆,將回復放到一個程序本身的緩衝區內,修改該文件描述符的註冊事件爲EPOLLIN|EPOLLOUT(視業務邏輯而定,若是要求必須應答發送以前不能接收請求,可只註冊EPOLLOUT事件),當EPOLLOUT觸發時,將回復發送出去,從緩衝區中刪除回覆,再修改該鏈接爲註冊EPOLLIN事件
即便在單線程程序中(運行在家用筆記本的虛擬機上),在3萬個鏈接的1萬個活動鏈接上,epoll也能夠一秒內收發100MB數據(已經接近於Gbit網卡的理論上限),因此若是沒有其它的IO活動或者計算處理,單線程的epoll徹底能夠應付高併發socket通訊
若是鏈接爆發,好比一秒1萬個,epoll server會在10+秒內accept完,不必擔憂它accept過慢,由於當監聽隊列不足時,tcp會忽略客戶端的SYN報文,這樣客戶端就會重傳,只要給客戶端設置一個合適的超時時間,例如15妙,epoll server處理每秒10000個新加鏈接沒有問題
-----通常處理模型
生產者消費者模式,一個線程單獨負責從監聽socket上accept,它收到新鏈接後,加鎖放入公共buffer,若干個工做線程加鎖從公共buffer上取得鏈接,加入本身的epoll等待集中,等待必定的時間,有數據則進行收發,沒數據繼續從公共buffer上取鏈接,可是這裏並不適用在線程間用條件變量通知,由於即便公共buffer上沒有新鏈接,工做線程也不該該等待accept線程通知,而是應當即用epoll wait本身已有的鏈接
不能採用多個線程自主搶佔鏈接的方式,數據在不一樣鏈接上是不均勻的,若是一些鏈接如今數據量如今過大,就會獲得不多的新鏈接,之後又會出現數據飢餓,而那些當時搶佔到過多鏈接的線程之後則會壓力過大,處理變慢。應該由單獨線程,例如負責accept的線程,分配到每一個線程本身的鏈接隊列中等待處理,另外,每一個處理線程都採用LT模式,每一個活動鏈接上輪流接收一次消息,而後就取回隊列中的新鏈接,若是採用ET模式,就可能一直忙於在舊鏈接上收發數據,而冷落新鏈接。
公司的網絡備份軟件,採用的是poll/select模型,由於客戶端一旦運行備份/恢復任務,在鏈接就必定有數據收發任務,這種狀況下,epoll不能加快性能
對於某些輸入io只有一路的程序,數據接收線程 + circle buffer + 數據處理線程是一個比較簡單的模型
上面的方案仍然形成數據量的線程處理不過來,數據量小的線程又很空閒,應該採用以下方案
主線程內用epoll接收數據和accept新鏈接,並解析出消息,放入隊列中讓全部的線程去搶,至於如何多個線程同時對一個鏈接發送消息,能夠採用與dedupe中多線程處理FP cache(一個hash table)的方案相似,分配與線程數目相同的鎖,當處理完消息須要發送時,將鏈接的文件描述符數除以線程數目,餘是多少,就加鎖哪一個鎖,這樣,多個線程能儘可能分配到不一樣的鎖上增長併發性,而對同一個鏈接加同一個鎖進行互斥的發送
另外,這還須要處理SIGPIPE消息,以避免前面一個線程關閉了鏈接,另外一個線程又去發送,產生SIGPIPE信號,使進程exit
原文:http://blog.csdn.net/piaoairy219/article/details/17398545