浅谈异步IO
我們已經(jīng)知道,CPU的速度遠(yuǎn)遠(yuǎn)快于磁盤、網(wǎng)絡(luò)等IO。在一個(gè)線程中,CPU執(zhí)行代碼的速度極快,然而,一旦遇到IO操作,如讀寫文件、發(fā)送網(wǎng)絡(luò)數(shù)據(jù)時(shí),就需要等待IO操作完成,才能繼續(xù)進(jìn)行下一步操作。這種情況稱為同步IO。
在IO操作的過程中,當(dāng)前線程被掛起,而其他需要CPU執(zhí)行的代碼就無法被當(dāng)前線程執(zhí)行了。
因?yàn)橐粋€(gè)IO操作就阻塞了當(dāng)前線程,導(dǎo)致其他代碼無法執(zhí)行,所以我們必須使用多線程或者多進(jìn)程來并發(fā)執(zhí)行代碼,為多個(gè)用戶服務(wù)。每個(gè)用戶都會(huì)分配一個(gè)線程,如果遇到IO導(dǎo)致線程被掛起,其他用戶的線程不受影響。
多線程和多進(jìn)程的模型雖然解決了并發(fā)問題,但是系統(tǒng)不能無上限地增加線程。由于系統(tǒng)切換線程的開銷也很大,所以,一旦線程數(shù)量過多,CPU的時(shí)間就花在線程切換上了,真正運(yùn)行代碼的時(shí)間就少了,結(jié)果導(dǎo)致性能嚴(yán)重下降。
由于我們要解決的問題是CPU高速執(zhí)行能力和IO設(shè)備的龜速嚴(yán)重不匹配,多線程和多進(jìn)程只是解決這一問題的一種方法。
另一種解決IO問題的方法是異步IO。當(dāng)代碼需要執(zhí)行一個(gè)耗時(shí)的IO操作時(shí),它只發(fā)出IO指令,并不等待IO結(jié)果,然后就去執(zhí)行其他代碼了。一段時(shí)間后,當(dāng)IO返回結(jié)果時(shí),再通知CPU進(jìn)行處理。
可以想象如果按普通順序?qū)懗龅拇a實(shí)際上是沒法完成異步IO的:
do_something() f = open('/path/to/file', 'r') r = f.read() # <==線程在此處停頓等待IO操作結(jié)果 # IO操作完成后線程才能繼續(xù)執(zhí)行 do_something_others()所以,同步IO模型的代碼是無法實(shí)現(xiàn)異步IO模型的。
異步IO模型需要一個(gè)消息循環(huán),在消息循環(huán)中,主線程不斷地重復(fù)“讀取消息-處理消息”這一過程:
loop = get_event_loop() while True:event = loop.get_event()process_event(event)消息模型其實(shí)早在應(yīng)用在桌面應(yīng)用程序中了。一個(gè)GUI程序的主線程就負(fù)責(zé)不停地讀取消息并處理消息。所有的鍵盤、鼠標(biāo)等消息都被發(fā)送到GUI程序的消息隊(duì)列中,然后由GUI程序的主線程處理。
由于GUI線程處理鍵盤、鼠標(biāo)等消息的速度非常快,所以用戶感覺不到延遲。某些時(shí)候,GUI線程在一個(gè)消息處理的過程中遇到問題導(dǎo)致一次消息處理時(shí)間過長(zhǎng),此時(shí),用戶會(huì)感覺到整個(gè)GUI程序停止響應(yīng)了,敲鍵盤、點(diǎn)鼠標(biāo)都沒有反應(yīng)。這種情況說明在消息模型中,處理一個(gè)消息必須非常迅速,否則,主線程將無法及時(shí)處理消息隊(duì)列中的其他消息,導(dǎo)致程序看上去停止響應(yīng)。
消息模型是如何解決同步IO必須等待IO操作這一問題的呢?當(dāng)遇到IO操作時(shí),代碼只負(fù)責(zé)發(fā)出IO請(qǐng)求,不等待IO結(jié)果,然后直接結(jié)束本輪消息處理,進(jìn)入下一輪消息處理過程。當(dāng)IO操作完成后,將收到一條“IO完成”的消息,處理該消息時(shí)就可以直接獲取IO操作結(jié)果。
在“發(fā)出IO請(qǐng)求”到收到“IO完成”的這段時(shí)間里,同步IO模型下,主線程只能掛起,但異步IO模型下,主線程并沒有休息,而是在消息循環(huán)中繼續(xù)處理其他消息。這樣,在異步IO模型下,一個(gè)線程就可以同時(shí)處理多個(gè)IO請(qǐng)求,并且沒有切換線程的操作。對(duì)于大多數(shù)IO密集型的應(yīng)用程序,使用異步IO將大大提升系統(tǒng)的多任務(wù)處理能力。
注:本文僅供學(xué)習(xí)借鑒,轉(zhuǎn)自https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/00143208573480558080fa77514407cb23834c78c6c7309000
總結(jié)
- 上一篇: 10实用的JS实用技巧
- 下一篇: python管理工具ports_Pyth