第四章 選擇器在本章中,我們將探索選擇器(selectors)。選擇器提供選擇執(zhí)行已經(jīng)就緒的任務(wù)的能力,這使得多元 I/O 成為可能。就像在第一章中描述的那樣,就緒選擇和多元執(zhí)行使得單線程能夠有效率地同時管理多個 I/O 通道(channels)。C/C++代碼的工具箱中,許多年前就已經(jīng)有 為了更好地說明就緒選擇,讓我們回到第三章的帶傳送通道的銀行的例子里。想象一下,一個有三個傳送通道的銀行。在傳統(tǒng)的(非選擇器)的場景里,想象一下每個銀行的傳送通道都有一個氣動導(dǎo)管,傳送到銀行里它對應(yīng)的出納員的窗口,并且每一個窗口與其他窗口是用墻壁分隔開的。這意味著每個導(dǎo)管(通道)需要一個專門的出納員(工作線程)。這種方式不易于擴展,而且也是十分浪費的。對于每個新增加的導(dǎo)管(通道),都需要一個新的出納員,以及其他相關(guān)的經(jīng)費,如表格、椅子、紙張的夾子(內(nèi)存、CPU 周期、上下文切換)等等。并且當(dāng)事情變慢下來時,這些資源(以及相關(guān)的花費)大多數(shù)時候是閑置的。 現(xiàn)在想象一下另一個不同的場景,每一個氣動導(dǎo)管(通道)都只與一個出納員的窗口連接。這個窗口有三個槽可以放置運輸過來的物品(數(shù)據(jù)緩沖區(qū)),每個槽都有一個指示器(選擇鍵,selection key),當(dāng)運輸?shù)奈锲愤M入時會亮起。同時想象一下出納員(工作線程)有一個花盡量多的時間閱讀《自己動手編寫個人檔案》一書的癖好。在每一段的最后,出納員看一眼指示燈(調(diào)用 雖然這種分析并不精確,但它描述了快速檢查大量資源中的任意一個是否需要關(guān)注,而在某些東西沒有準(zhǔn)備好時又不必被迫等待的通用模式。這種檢查并繼續(xù)的能力是可擴展性的關(guān)鍵,它使得僅僅使用單一的線程就可以通過就緒選擇來監(jiān)控大量的通道。 選擇器及相關(guān)的類就提供了這種API,使得我們可以在通道上進行就緒選擇。 4.1 選擇器基礎(chǔ)掌握本章中討論的主題,在某種程度上,比直接理解緩沖區(qū)和通道類更困難一些。這會復(fù)雜一些,因為涉及了三個主要的類,它們都會同時參與到整個過程中。如果您發(fā)現(xiàn)自己有些困惑,記錄下來并先看其他內(nèi)容。一旦您了解了各個部分是如何相互適應(yīng)的,以及每個部分扮演的角色,您就會理解這些內(nèi)容了。 我們會先從總體開始,然后分解為細節(jié)。您需要將之前創(chuàng)建的一個或多個可選擇的通道注冊到選擇器對象中。一個表示通道和選擇器的鍵將會被返回。選擇鍵會記住您關(guān)心的通道。它們也會追蹤對應(yīng)的通道是否已經(jīng)就緒。當(dāng)您調(diào)用一個選擇器對象的 這是在3000英尺高的地方看到的情景。現(xiàn)在,讓我們看看在地面上(甚至地下)到底發(fā)生了什么。 現(xiàn)在,您可能已經(jīng)想要跳到例 4-1,并快速地瀏覽一下代碼了。通過在這里和那段代碼之間的內(nèi)容,您將學(xué)到這些新類是如何工作的。在掌握了前面的段落里的高層次的信息之后,您需要了解選擇器模型是如何在實踐中被使用的。 從最基礎(chǔ)的層面來看,選擇器提供了詢問通道是否已經(jīng)準(zhǔn)備好執(zhí)行每個I/0操作的能力。例如,我們需要了解一個 在與 乍一看,好像只要非阻塞模式就可以模擬就緒檢查功能,但實際上還不夠。非阻塞模式同時還會執(zhí)行您請求的任務(wù),或指出它無法執(zhí)行這項任務(wù)。這與檢查它是否能夠執(zhí)行某種類型的操作是不同的。舉個例子,如果您試圖執(zhí)行非阻塞操作,并且也執(zhí)行成功了,您將不僅僅發(fā)現(xiàn) 效率上的要求使得您不能將檢查就緒的代碼和處理數(shù)據(jù)的代碼分離開來,至少這么做會很復(fù)雜。 即使簡單地詢問每個通道是否已經(jīng)就緒的方法是可行的,在您的代碼或一個類庫的包里的某些代碼需要遍歷每一個候選的通道并按順序進行檢查的時候,仍然是有問題的。這會使得在檢查每個通道是否就緒時都至少進行一次系統(tǒng)調(diào)用,這種代價是十分昂貴的,但是主要的問題是,這種檢查不是原子性的。列表中的一個通道都有可能在它被檢查之后就緒,但直到下一次輪詢?yōu)橹?,您并不會覺察到這種情況。最糟糕的是,您除了不斷地遍歷列表之外將別無選擇。您無法在某個您感興趣的通道就緒時得到通知。 這就是為什么傳統(tǒng)的監(jiān)控多個socket的Java解決方案是為每個socket創(chuàng)建一個線程并使得線程可以在 真正的就緒選擇必須由操作系統(tǒng)來做。操作系統(tǒng)的一項最重要的功能就是處理I/O請求并通知各個線程它們的數(shù)據(jù)已經(jīng)準(zhǔn)備好了。選擇器類提供了這種抽象,使用Java代碼能夠以可移植的方式,請求底層的操作系統(tǒng)提供就緒選擇服務(wù)。 讓我們看一下
0
0
我們認為:用戶的主要目的,是為了獲取有用的信息,而不是來點擊廣告的。因此本站將竭力做好內(nèi)容,并將廣告和內(nèi)容進行分離,確保所有廣告不會影響到用戶的正常閱讀體驗。用戶僅憑個人意愿和興趣愛好點擊廣告。
我們堅信:只有給用戶帶來價值,用戶才會給我們以回報。 |
|