個(gè)人名片:
🐼作者簡介:一名大二在校生,喜歡編程🎋
🐻???個(gè)人主頁🥇:小新愛學(xué)習(xí).
🐼個(gè)人WeChat:hmmwx53
🕊?系列專欄:🖼?
- 零基礎(chǔ)學(xué)Java——小白入門必備
- 重識C語言——復(fù)習(xí)回顧
- 計(jì)算機(jī)網(wǎng)絡(luò)體系———深度詳講
- 微信小程序開發(fā)——實(shí)戰(zhàn)開發(fā)
🐓每日一句:🍭我很忙,但我要忙的有意義!
IO 模型是指計(jì)算機(jī)在涉及 I/O 操作時(shí)使用到的模型。為了解決各種問題,人們提出了很多不同的 I/ 模型,與之相關(guān)的概念有線程、阻塞、非阻塞、同步以及異步等。I/O 可以分成阻塞IO 與非寨I/O 兩大類型。阻塞 I/O 在進(jìn)行 操作時(shí)會(huì)使當(dāng)前線程進(jìn)入阻塞狀態(tài),而非阻塞IO 則不進(jìn)人阻寨狀態(tài)。以服務(wù)器處理客戶端連接為例,在單線程情況下由一個(gè)線程負(fù)責(zé)所有客戶端連接的I/O操作,而在多線程情況下則由若干線程共同處理所有客戶端連接的I/O操作。
此外,需要注意的是,計(jì)算機(jī)的I/O 其實(shí)包含了各種設(shè)備的 IO,比如網(wǎng)絡(luò) IO、磁盤IO鍵盤I/O 和鼠標(biāo)IO等。我們以經(jīng)典的網(wǎng)絡(luò) I/O 場景(見圖 2.1)為例來講解單線程阻塞IO模型和多線程阻塞 IO 模型。
程序在執(zhí)行 I/O 時(shí)一般需要從內(nèi)核空間復(fù)制數(shù)據(jù),但內(nèi)核空間的數(shù)據(jù)可能需要較長時(shí)間進(jìn)行準(zhǔn)備,由此導(dǎo)致用戶空間產(chǎn)生阻塞。在圖 2.2 中,應(yīng)用程序處于用戶空間,一個(gè)應(yīng)用程序?qū)?yīng)著一個(gè)進(jìn)程,而進(jìn)程則包含了緩沖區(qū)。當(dāng)要進(jìn)行I/O 操作時(shí),需要通過內(nèi)核來執(zhí)行相應(yīng)的操作,比如由內(nèi)核負(fù)責(zé)與鍵盤、磁盤、網(wǎng)絡(luò)等控制器進(jìn)行通信。當(dāng)內(nèi)核得到不同設(shè)備的控制器發(fā)送過來的數(shù)據(jù)后,會(huì)將數(shù)據(jù)復(fù)制到用戶空間供應(yīng)用程序使用。
網(wǎng)絡(luò)I/O產(chǎn)生阻塞的過程如圖 2.3 所示。應(yīng)用程序首先發(fā)起讀取操作,然后進(jìn)入阻塞狀態(tài)接下來由操作系統(tǒng)內(nèi)核完成IO 操作。內(nèi)核剛開始時(shí)未準(zhǔn)備好數(shù)據(jù)它需要不斷讀取網(wǎng)絡(luò)數(shù)據(jù)一旦數(shù)據(jù)準(zhǔn)備好,就將數(shù)據(jù)復(fù)制到用戶空間供應(yīng)用程序使用。應(yīng)用程序在從發(fā)起讀取操作到繼續(xù)往下處理的這段時(shí)間就處于阻塞狀態(tài)。
單線程阻塞 I/O模型是最簡單的一種服務(wù)器模型,幾乎所有程序員在剛開始接觸網(wǎng)絡(luò)編程時(shí)都從這種模型開始。這種模型只能同時(shí)處理一個(gè)客戶端訪問,并且在 I/O 操作上是阻塞的線程會(huì)一直處于等待狀態(tài)而不會(huì)做其他事情。對于多個(gè)客戶端訪問的情況,必須要等到前一個(gè)客戶端訪問結(jié)束后才能進(jìn)行下一個(gè)訪問的處理。也就是說,請求一個(gè)一個(gè)排隊(duì),且只提供一問一答服務(wù)。
圖2.4所示為單線程阻塞服務(wù)器響應(yīng)客戶端訪問的時(shí)間節(jié)點(diǎn)。首先,服務(wù)器必須初始化一個(gè)套接宇(socket)服務(wù)器,并綁定某個(gè)端口號使之監(jiān)聽客戶端的訪問。接著,客戶端1 調(diào)用服務(wù)器的服務(wù),服務(wù)器接收到請求后對其進(jìn)行處理,處理完后寫數(shù)據(jù)回客戶端1。最后,處理客戶端2的請求并寫數(shù)據(jù)回客戶端 2,期間即使客戶端 2 在服務(wù)器處理完客戶端1之前就進(jìn)行請求,也要等服務(wù)器對客戶端1 響應(yīng)完后才會(huì)對客戶端 2 進(jìn)行響應(yīng)處理。
這種模型的特點(diǎn)在于單線程和阻塞 I/O。單線程即服務(wù)器端只有一個(gè)線程處理客戶端的所有請求,客戶端連接與服務(wù)器端的處理線程比是 n:1,它無法同時(shí)處理多個(gè)連接,只能串行處理連接。而阻塞I/O 是指服務(wù)器在讀寫數(shù)據(jù)時(shí)是阻塞的,在讀取客戶端數(shù)據(jù)時(shí)要等待客戶端發(fā)送數(shù)據(jù)并且把操作系統(tǒng)內(nèi)核中的數(shù)據(jù)復(fù)制到用戶進(jìn)程中,這時(shí)才解除阻塞狀態(tài)。將數(shù)據(jù)寫回客戶端時(shí)要等待用戶進(jìn)程將數(shù)據(jù)寫入內(nèi)核后才解除阻塞狀態(tài)。
單線程阻塞IO 模型是最簡單的一種服務(wù)器模型,整個(gè)運(yùn)行過程都只有一個(gè)線程,只能同時(shí)處理一個(gè)客戶端的請求(如果有多個(gè)客戶端訪問,就必須排隊(duì)等待 )。服務(wù)器系統(tǒng)資源消耗較小,但并發(fā)能力低,容錯(cuò)能力差。
針對單線程阻塞 IO 模型的缺點(diǎn),最簡單的改進(jìn)方式就是將其多線程化,使之能對多個(gè)客戶端進(jìn)行并發(fā)響應(yīng)。多線程模型的核心就是利用多線程機(jī)制為每個(gè)客戶端分配一個(gè)線程。如圖 2.5所示,服務(wù)器端開始監(jiān)聽客戶端的訪問,假如有兩個(gè)客戶端發(fā)送請求過來,服務(wù)器端在接收到客戶端請求后將創(chuàng)建兩個(gè)線程分別對它們進(jìn)行處理。每個(gè)線程負(fù)責(zé)一個(gè)客戶端連接,直到響應(yīng)完成。期間兩個(gè)線程并發(fā)地為各自對應(yīng)的客戶端處理請求,包括讀取客戶端數(shù)據(jù)、處理客戶端數(shù)據(jù)、將數(shù)據(jù)寫回客戶端等操作。
這種模型的I/O操作也是阻塞的,因?yàn)槊總€(gè)線程執(zhí)行到讀取或?qū)懭氩僮鲿r(shí)都將進(jìn)入阻塞狀態(tài),直到成功讀取客戶端的數(shù)據(jù)或數(shù)據(jù)成功寫入內(nèi)核后才解除阻塞狀態(tài)。盡管此時(shí)的 IO 操作還是會(huì)阻塞,但這種模式比單線程模式的性能明顯提高,它不用等到第一個(gè)請求處理完才處理第二個(gè),而是并發(fā)地處理客戶端請求,客戶端連接與服務(wù)器端處理線程的關(guān)系是一對一的。多線程阻塞 IO 模型的特點(diǎn)如下所示:
前面講到,多線程陽塞 I/O 模型通過引入多線程的方法來提升服務(wù)器端的并發(fā)處理能力確實(shí)能夠達(dá)到一定的效果。但它還是存在一個(gè)嚴(yán)重的問題,那就是每個(gè)連接都需要一個(gè)線程負(fù)責(zé)I/O 操作。當(dāng)連接數(shù)量較多時(shí)將導(dǎo)致機(jī)器線程數(shù)量太多,而這些線程在大多數(shù)時(shí)間內(nèi)都處干等待狀態(tài),線程之間的切換成本非常高。對于多線程阻塞 I/O 模型的這個(gè)缺點(diǎn),有沒有可能只用一個(gè)線程就可以維護(hù)多個(gè)客戶端連接并且不會(huì)阻塞在讀寫操作呢?這就是下面要介紹的單線程非阻塞I/O模型。
就單線程非阻塞 IO模型來說,與阻塞 IO型相同的地方是,程序在執(zhí)行 I/O 時(shí)一般要從內(nèi)核空間和用戶空問復(fù)制數(shù)據(jù),不同之處在于非阻塞 I/O 模型不會(huì)一直等到內(nèi)核準(zhǔn)備好需據(jù)、而是直接返回去做其他的事,也就是說并不產(chǎn)生阻塞。應(yīng)用程序進(jìn)程包含一個(gè)緩沖區(qū),詳個(gè)線得會(huì)不斷循環(huán)濫用所有客戶端,嘗試對它們進(jìn)行讀寫操作。如果內(nèi)核已準(zhǔn)備好數(shù)據(jù),那么應(yīng)用層線程就會(huì)將數(shù)據(jù)復(fù)制到用戶空間供使用,如圖 2.6 所示
非阻塞I/O 模型最重要的一個(gè)特點(diǎn)是在調(diào)用讀或?qū)懡涌诤髸?huì)立即返回,而不會(huì)進(jìn)入阻塞狀態(tài)。網(wǎng)絡(luò)的非阻塞I/O 的過程如圖 2.7 所示。應(yīng)用程序首先發(fā)起讀取操作,它會(huì)告知操作系統(tǒng)內(nèi)核去執(zhí)行IO 操作。剛開始時(shí)由于內(nèi)核未準(zhǔn)備好數(shù)據(jù),所以會(huì)馬上返回而不是阻塞。此時(shí)應(yīng)用程序可以做其他事,過一段時(shí)間后再嘗試讀取操作。如果發(fā)現(xiàn)數(shù)據(jù)已經(jīng)準(zhǔn)備好,內(nèi)核就將數(shù)據(jù)復(fù)制到用戶空間供應(yīng)用程序使用。
非阻塞 I/O模型可分為應(yīng)用層 I/O 多路復(fù)用、內(nèi)核 I/O 多路復(fù)用、內(nèi)核回調(diào)事件驅(qū)動(dòng) I/O這3種。
雖然現(xiàn)代計(jì)算機(jī)都是多 CPU 的,而且操作系統(tǒng)也提供了多線程機(jī)制,但并不是說單線程完全被拋棄,實(shí)際上單線程也有自己的優(yōu)勢。大的優(yōu)勢就是一個(gè) CPU 只負(fù)責(zé)一個(gè)線程,因此可以完全規(guī)避多線程中的所有疑難雜癥,這樣在編寫代碼時(shí)就簡單多了,如圖 2.12 所示。比如在以前的多線程環(huán)境中,共享變量的操作要考慮很多問題,而單線程則不必考慮這些。同時(shí)單線程也免去了線程上下文的切換,進(jìn)一步提高了 CPU 的真正使用率。
在一個(gè)線程對應(yīng)一個(gè) CPU 的情況下,如果多核計(jì)算機(jī)中只執(zhí)行一個(gè)線程,那么就只有一個(gè) CPU 工作,這樣也就無法充分利用 CPU 資源。為了解決這個(gè)問題,我們的程序可以根據(jù)CPU的數(shù)量來創(chuàng)建線程數(shù),N個(gè) CPU分別對應(yīng)N個(gè)線程,如圖 2.13 所示。這種模型充分利用了多個(gè) CPU,同時(shí)也保持了單線程的優(yōu)點(diǎn),相當(dāng)于多個(gè)線程并行執(zhí)行而不是并發(fā)執(zhí)行。
在多核的機(jī)器時(shí)代,多線程和非阻塞都是提升服務(wù)器處理性能的利器。那么如何將它們結(jié)合起來呢?最常規(guī)的做法就是將客戶端連接按組分配給若干線程,每個(gè)線程負(fù)責(zé)處理對應(yīng)組內(nèi)的連接。如圖 2.14 所示,有 4 個(gè)客戶端訪問服務(wù)器,服務(wù)器將 socketl 和 socket2 交由線程管理,而線程 2則管理 socket3 和 socket4,通過事件檢測及非阻塞讀寫就可以讓每個(gè)線程都能高效運(yùn)行。
在實(shí)際的工程中,最經(jīng)典的多線程非阻塞 I/O 模式是 Reactor 模式。首先看單線程下的Reactor。Reactor 將服務(wù)器端的整個(gè)處理過程分成若干個(gè)事件,例如分為接收事件、讀事件、寫事件、執(zhí)行事件等。Reactor 通過事件檢測機(jī)制將這些事件分發(fā)給不同的處理器去處理。如圖2.15 所示,若干客戶端連接訪問服務(wù)器端,Reactor 負(fù)責(zé)檢測各種事件并分發(fā)到處理器,這些處理器包括接收連接的 accept 處理器、讀數(shù)據(jù)的 read 處理器、寫數(shù)據(jù)的 write 處理器以及執(zhí)行邏輯的 process 處理器。在整個(gè)過程中只要有待處理的事件存在,就可以讓 Reactor 線程不斷往下執(zhí)行,而不會(huì)阻塞在某處,所以處理效率很高。
基于單線程的 Reactor 模式在實(shí)際中很少使用,我們更多地是將它改進(jìn)為多線程模式。常見的有下面兩種:
Reactor 模式的第一種改進(jìn)方式是多線程 Reactor 模式,如圖 2.16 所示。多線程 Reactor 模式的整體結(jié)構(gòu)基本與單線程的 Reactor 類似,只是額外引人了一個(gè)線程池。由于對連接的接收對數(shù)據(jù)的讀取和對數(shù)據(jù)的寫人等操作基本上都耗時(shí)較少,因此把它們都放到 Reactor 線程中處理。然而,對于可能比較耗時(shí)的邏輯處理工作,則在 process 處理器中引入線程池。process 處理器自己不執(zhí)行任務(wù),而是交給線程池,從而在 Reactor 線程中避免了耗時(shí)的操作。將耗時(shí)的操作轉(zhuǎn)移到線程池中后,盡管 Reactor 只有一個(gè)線程,也能保證 Reactor 的高效性。
Reactor模式的第二種改進(jìn)方式是多 Reactor 實(shí)例模式,如圖2.17 所示。其中有多個(gè) Reactor實(shí)例,每個(gè) Reactor 實(shí)例對應(yīng)一個(gè)線程。因?yàn)榻邮帐录窍鄬τ诜?wù)器端而言的,所以客戶端的連接接收工作統(tǒng)一由一個(gè)accept 處理器負(fù)責(zé),accept 處理器會(huì)將接收的客戶端連接均勻分配給所有 Reactor 實(shí)例。每個(gè) Reactor 實(shí)例負(fù)責(zé)處理分配到該 Reactor 上的客戶端連接,包括連接的讀數(shù)據(jù)、寫數(shù)據(jù)和邏輯處理。這就是多 Reactor 實(shí)例的原理。
并發(fā)和并行都是相對于進(jìn)程或線程來說的。并發(fā)是指一個(gè)或若干個(gè) CPU 對多個(gè)進(jìn)程或線程進(jìn)行多路復(fù)用,用簡單的語言來說就是 CPU 交替執(zhí)行多個(gè)任務(wù),每個(gè)任務(wù)都執(zhí)行一小段時(shí)間,從宏觀上看,就像是全部任務(wù)都在同時(shí)執(zhí)行一樣。
👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇
你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級服務(wù)器適合批量采購,新人活動(dòng)首月15元起,快前往官網(wǎng)查看詳情吧
當(dāng)前名稱:【Java多線程編程|從0到1】線程I/O模型-創(chuàng)新互聯(lián)
分享URL:http://jinyejixie.com/article24/djsjje.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供企業(yè)網(wǎng)站制作、網(wǎng)站改版、網(wǎng)站維護(hù)、微信公眾號、定制網(wǎng)站、網(wǎng)站排名
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容