小小書童記錄select

小記:

阻塞,非阻塞:進程/線程要訪問的數(shù)據(jù)是否就緒,進程/線程是否需要等待;
同步,異步:訪問數(shù)據(jù)的方式,同步需要主動讀寫數(shù)據(jù),在讀寫數(shù)據(jù)的過程中還是會阻塞;異步只需要I/O操作完成的通知,并不主動讀寫數(shù)據(jù),由操作系統(tǒng)內(nèi)核完成數(shù)據(jù)的讀寫。

Select IO復(fù)用模型是上個世紀90年代的東西,受限于當(dāng)時的計算機硬軟件的限制,這種技術(shù)隨著epoll的出現(xiàn)逐漸被取代,但它畢竟風(fēng)光過。了解歷史才能更好的展望未來,每一個有情懷的碼農(nóng)都不應(yīng)該一味抬頭看遠方,時而低頭凝視大地,不亦樂乎~

了解select之前,我們需要了解下位圖(bitmap),bitmap其實就是將對象映射到具體的一個bit位上來,表示對象存在或者被標記。bitmap算法有節(jié)省內(nèi)存和快速查詢等特點,所以適合處理海量數(shù)據(jù)的排序和查詢。這種古老而牛逼的技術(shù)在數(shù)據(jù)庫,操作系統(tǒng)上都有很廣泛的應(yīng)用。好的,下面引入select中使用到bitmap算法的幾個API函數(shù),也是在使用select這種IO復(fù)用技術(shù)時經(jīng)常使用到的。

int FD_ZERO(fd_set *fdset);    // 復(fù)位
int FD_CLR(int fd, fd_set *fdset);   // 清零
int FD_SET(int fd, fd_set *fd_set);   // 設(shè)置
int FD_ISSET(int fd, fd_set *fdset);  // 測試設(shè)置

這幾個函數(shù)主要完成具體 fdfd_set rset 映射關(guān)系的處理??聪?code>fd_set的存儲結(jié)構(gòu):

#ifndef FD_SETSIZE
#define FD_SETSIZE  1024
#endif

#define NBBY    8       /* number of bits in a byte */
typedef long    fd_mask;
#define NFDBITS (sizeof (fd_mask) * NBBY)   /* bits per mask */
#define howmany(x,y)    (((x)+((y)-1))/(y))

typedef struct _types_fd_set {
    fd_mask fds_bits[howmany(FD_SETSIZE, NFDBITS)];
} _types_fd_set;

清楚的看到,一個long類型8個字節(jié),這樣fds_bits就有1024/64 = 16 即16個64bit的數(shù)組,每一個數(shù)組64bit。設(shè)置和清零這兩個操作是位操作,很方便,自己寫了一個BitMapGolang代碼,這里也順便貼出:

func (b *BitSet) Set(i uint) {
        ....
    b.set[i>>6] = b.set[i>>6] | (1 << (i & (64 - 1)))
}
func (b *BitSet) Clear(i uint) {
    ....
    b.set[i>>6] &^= 1 << (i & (64 - 1))
}

好了,知道fdset的存儲結(jié)構(gòu)和簡單設(shè)置之后,可以看下selectIO模型中的另外一個API:

int select(int maxfdp, fd_set *readset, fd_set *writeset, fd_set *exceptset,struct timeval *timeout);

其中有兩個參數(shù)需要說明下:

  1. 第一個參數(shù)是timeout, 它代表select超時時間。該值有三種狀態(tài):timeout == NULL 無條件等待。 select函數(shù)將返回 -1, erro設(shè)為 EINTR,表示被迫中斷。timeout->tv_sec == 0 &&timeout->tv_usec == 0 不等待,直接返回。timeout->tv_sec != 0 || timeout->tv_usec != 0 等待指定的時間,select返回0表示在規(guī)定時間內(nèi)沒有fd讀寫或者異常事件發(fā)生。
struct timeval  {
        long tv_sec;   /*秒 */
        long tv_usec;  /*微秒 */   
}
  1. 第二個參數(shù) maxfdp,這個是文件描述符fd的最大值加1。每次調(diào)用select之前都需要算出最大的fd,作為maxfd。

關(guān)于select的內(nèi)核實現(xiàn)部分,網(wǎng)上有很多文章進行了詳細的描述,這里就不再贅述。好的,這里還是不落俗套地提下select的缺點:<1> 描述符(FD)數(shù)量問題 。<2> IO效率隨FD的增加而線性下降。select隨FD的增加性能下降的問題, 在使用方式上可以感受到:用戶態(tài)需要每次select之前復(fù)位所有fd,然后select之后還得遍歷所有fd找到可讀寫或異常的fd。但至今沒有對select做過benchmark。

這里隨便帶上poll小弟:

int poll (struct pollfd *fds, unsigned int nfds, int timeout);

其中pollfd的數(shù)據(jù)結(jié)構(gòu):

struct pollfd {
    int fd; /* file descriptor */
    short events; /* requested events to watch */
    short revents; /* returned events witnessed */
};

poll方式并沒有采用selectfdset方式,而是每一個fd都有一個自己的pollfd數(shù)據(jù)結(jié)構(gòu),里面存放除了fd外,還存放events事件類型,這樣poll就沒有fd個數(shù)的上限問題了,但它仍然需要遍歷fds拿到可讀寫或異常的fd。這點跟select還是一樣的。

好了,小小書童簡單記錄下,end~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 一、概述 I/O復(fù)用使得程序能同時監(jiān)聽多個文件描述符,這對提高程序的性能至關(guān)重要。 I/O復(fù)用雖然能同時監(jiān)聽多個文...
    saviochen閱讀 1,259評論 0 4
  • 本文摘抄自linux基礎(chǔ)編程 IO概念 Linux的內(nèi)核將所有外部設(shè)備都可以看做一個文件來操作。那么我們對與外部設(shè)...
    lintong閱讀 1,685評論 0 4
  • 串口操作 串口操作需要的頭文件 #include /*標準輸入輸出定義*/ #include /*標準函數(shù)庫定...
    旅行家John閱讀 1,469評論 0 3
  • 一個工作日的下午,至少對別人而言是工作日。一個人躺在沙發(fā)上,心里突然空落落的。 我是沐小熙,剛從電話銷售公司離職。...
    沐小熙閱讀 347評論 0 0
  • 你說 要用巖石建造一座神殿 不要門窗 你說 要把自己的心囚禁其中 再不讓世俗打擾 你說 陽光可以為你照明 雨露可以...
    簡JN閱讀 297評論 2 12

友情鏈接更多精彩內(nèi)容