參考文章:
1.廖雪峰教程-異步
3.Improve Your Python: 'yield' and Generators Explained
4.[譯] Python 3.5 協(xié)程究竟是個(gè)啥
概念:同步、異步、阻塞、非阻塞
請(qǐng)參見(jiàn)我的之前的學(xué)習(xí)筆記為什么要使用異步?
CPU和IO的速度差異大,為了同時(shí)執(zhí)行其他的任務(wù),我們可以采用多線程和多進(jìn)程,也可以采用異步,正如上面的學(xué)習(xí)筆記,異步是一種分離調(diào)用和結(jié)果兩個(gè)過(guò)程的機(jī)制,因此可以用異步來(lái)解決IO問(wèn)題。Coroutines and Subroutines 協(xié)程和子程序
見(jiàn)上面的參考文章3
子程序就是協(xié)程的一種特例
協(xié)程和子程序一樣都可以跟主程序進(jìn)行交互,但是協(xié)程可以保存上下文。
- 消息模型是如何解決同步IO必須等待IO操作這一問(wèn)題的呢?
當(dāng)遇到IO操作時(shí),代碼只負(fù)責(zé)發(fā)出IO請(qǐng)求,不等待IO結(jié)果,然后直接結(jié)束本輪消息處理,進(jìn)入下一輪消息處理過(guò)程。當(dāng)IO操作完成后,將收到一條“IO完成”的消息,處理該消息時(shí)就可以直接獲取IO操作結(jié)果。
- 優(yōu)點(diǎn)
在“發(fā)出IO請(qǐng)求”到收到“IO完成”的這段時(shí)間里,同步IO模型下,主線程只能掛起,但異步IO模型下,主線程并沒(méi)有休息,而是在消息循環(huán)中繼續(xù)處理其他消息。這樣,在異步IO模型下,一個(gè)線程就可以同時(shí)處理多個(gè)IO請(qǐng)求,并且沒(méi)有切換線程的操作。對(duì)于大多數(shù)IO密集型的應(yīng)用程序,使用異步IO將大大提升系統(tǒng)的多任務(wù)處理能力。
- 協(xié)程
協(xié)程看上去也是子程序,但執(zhí)行過(guò)程中,在子程序內(nèi)部可中斷,然后轉(zhuǎn)而執(zhí)行別的子程序,在適當(dāng)?shù)臅r(shí)候再返回來(lái)接著執(zhí)行。
- 那和多線程比,協(xié)程有何優(yōu)勢(shì)?
最大的優(yōu)勢(shì)就是協(xié)程極高的執(zhí)行效率。因?yàn)樽映绦蚯袚Q不是線程切換,而是由程序自身控制,因此,沒(méi)有線程切換的開(kāi)銷(xiāo),和多線程比,線程數(shù)量越多,協(xié)程的性能優(yōu)勢(shì)就越明顯。
- 實(shí)例
import asyncio
@asyncio.coroutine
def getdata():
print('getting data!')
r = yield from asyncio.sleep(1)
print('has got data!')
def main():
loop = asyncio.get_event_loop()
loop.run_until_complete(getdata())
loop.close()
if __name__ == '__main__':
main()
首先我們需要一個(gè)處理循環(huán)loop,這個(gè)就是前面說(shuō)異步的時(shí)候說(shuō)的調(diào)用者,相對(duì)IO來(lái)說(shuō)執(zhí)行的非??欤梢詧?zhí)行多個(gè)協(xié)程。協(xié)程是循環(huán)的小弟,幫loop去執(zhí)行不同的調(diào)用,比如這里的getdata,r = yield from asyncio.sleep(1)這句就相對(duì)于IO操作,調(diào)用后馬上返回loop,loop繼續(xù)處理,知道IO處理好之后,loop就回到協(xié)程的這里繼續(xù)執(zhí)行。注意調(diào)用和數(shù)據(jù)返回是分開(kāi)的
- 例子2
import asyncio
import threading
@asyncio.coroutine
def getdata():
print('getting data in thread {}...'.format(threading.current_thread()))
r = yield from asyncio.sleep(1)
print('has got data!')
def main():
loop = asyncio.get_event_loop()
coroutines = [getdata(),getdata()]
loop.run_until_complete(asyncio.wait(coroutines))
loop.close()
if __name__ == '__main__':
main()
打印出的信息
getting data in thread <_MainThread(MainThread, started 3704)>...
getting data in thread <_MainThread(MainThread, started 3704)>...
has got data!
has got data!
這個(gè)例子說(shuō)明,多個(gè)協(xié)程是在同一個(gè)線程中運(yùn)行的,協(xié)程用于異步IO的驗(yàn)證
廖雪峰還用了一個(gè)網(wǎng)絡(luò)并發(fā)的例子,可以去看看
asyncio可以實(shí)現(xiàn)單線程并發(fā)IO操作。如果僅用在客戶端,發(fā)揮的威力不大。如果把a(bǔ)syncio用在服務(wù)器端,例如Web服務(wù)器,由于HTTP連接就是IO操作,因此可以用單線程+coroutine實(shí)現(xiàn)多用戶的高并發(fā)支持。
asyncio實(shí)現(xiàn)了TCP、UDP、SSL等協(xié)議,aiohttp則是基于asyncio實(shí)現(xiàn)的HTTP框架。
拓展閱讀:
1.Python 異步網(wǎng)絡(luò)爬蟲(chóng) I
2.Python 異步網(wǎng)絡(luò)爬蟲(chóng) II