協(xié)程與多進(jìn)程的完美結(jié)合
我們知道,協(xié)程本質(zhì)上是單線程單進(jìn)程,通過充分利用IO等待時(shí)間來實(shí)現(xiàn)高并發(fā)。在IO等待時(shí)間之外的代碼,還是串行運(yùn)行的。因此,如果協(xié)程非常多,多少每個(gè)協(xié)程內(nèi)部的串行代碼運(yùn)行時(shí)間超過了IO請(qǐng)求的等待時(shí)間,那么它的并發(fā)就會(huì)有一個(gè)上限。
舉個(gè)例子,電飯煲煮飯,洗衣機(jī)洗衣服,熱水壺?zé)?,他們都是啟?dòng)設(shè)備以后就能自己運(yùn)行,我們可以利用他們自己運(yùn)行的時(shí)間,讓這三件事情看起來幾乎在同時(shí)進(jìn)行。但如果除了這三件事情外,還有開電視,開空調(diào),發(fā)微信……等等幾十個(gè)事情。每個(gè)事情單獨(dú)拿出來確實(shí)都只需要做個(gè)開頭,剩下的就是等,但由于做這個(gè)開頭也需要時(shí)間,因此把他們?nèi)繂?dòng)起來也要不少時(shí)間,你的效率還是被卡住。
現(xiàn)在,如果有兩個(gè)人一起來做這些事情,那情況就不一樣了。一個(gè)人煮飯和燒水,另一個(gè)人開洗衣機(jī),開電視和空調(diào)。效率進(jìn)一步提升。
這就是協(xié)程與多進(jìn)程的結(jié)合,每個(gè)進(jìn)程里面多個(gè)協(xié)程同時(shí)運(yùn)行,充分利用CPU的每一個(gè)核心,又充分利用了IO等待時(shí)間,把CPU跑滿,把網(wǎng)絡(luò)帶寬跑滿。強(qiáng)強(qiáng)聯(lián)合,速度更快。
有一個(gè)第三方庫aiomultiprocess,讓你能用幾行代碼就實(shí)現(xiàn)多進(jìn)程與協(xié)程的組合。
首先使用pip安裝:
python3 -m pip install aiomultiprocess
它的語法非常簡(jiǎn)單:
from aiomultiprocess import Pool
async with Pool() as pool:
results = await pool.map(協(xié)程, 參數(shù)列表)
只需要3行代碼,它就會(huì)在你CPU上每個(gè)核啟動(dòng)一個(gè)進(jìn)程,每個(gè)進(jìn)程中不停啟動(dòng)協(xié)程。
我們來寫一段實(shí)際代碼:
import asyncio
import httpx
from aiomultiprocess import Pool
async def get(url):
async with httpx.AsyncClient() as client:
resp = await client.get(url)
return resp.text
async def main():
urls = [url1, url2, url3]
async with Pool() as pool:
async for result in pool.map(get, urls):
print(result) # 每一個(gè)URL返回的內(nèi)容
if __name__ == '__main__':
asyncio.run(main())
之前我寫異步協(xié)程文章的時(shí)候,有些人同學(xué)會(huì)問我,爬蟲的速度真的那么重要嗎?難道不是突破反爬蟲最重要嗎?
我的回答是,不要看到用aiohttp請(qǐng)求網(wǎng)址就覺得是做爬蟲。在微服務(wù)里面,自己請(qǐng)求自己的HTTP接口,也需要使用httpx或者aiohttp。在這樣的場(chǎng)景里面,速度就是非常的重要,有時(shí)候就是需要做到越快越好。