asyncio
先看一個(gè)小例子
#!/usr/bin/env python3.6
import asyncio
# python3.5開始用async代替了asyncio.coroutine拗秘, await 代替了yield from
async def hello():
print("hello world!")
# 使用asyncio.sleep()而不是time.sleep()才沧,因?yàn)楹笳呤亲枞偷? # await后面的表達(dá)式是一個(gè)生成器
# r = yield asyncio.sleep(1)
r = await asyncio.sleep(1)
print("end")
# 創(chuàng)建事件偱環(huán)
loop = asyncio.get_event_loop()
# 將hello函數(shù)放到事件偱環(huán)中執(zhí)行
loop.run_until_complete(hello())
loop.close()
Task對(duì)象
- 用來驅(qū)動(dòng)協(xié)程,使用loop.create_task(...)或asyncio.ensure_task(...)獲取
- Task是Future的子類,與Concurrent.futures.Future類似
- run_until_complete函數(shù)會(huì)自動(dòng)將協(xié)程轉(zhuǎn)換成Task對(duì)象,然后執(zhí)行
- 獲取最終結(jié)果是用result = await task_obj 而不是result = task_obj.result()
幾個(gè)重要的方法
- asyncio.ensure_task(coro_or_future, loop=None)
接收一個(gè)協(xié)程或Future對(duì)象,如果是協(xié)程臂港,則會(huì)調(diào)用loop.create_task()方法創(chuàng)建Future對(duì)象,如果是Future或Task對(duì)象视搏,則會(huì)直接返回。loop是可選參數(shù)县袱,如果沒有傳遞浑娜,ensure_task方法會(huì)使用get_event_loop創(chuàng)建loop
異步爬蟲庫 aiohttp
#!/usr/bin/env python3.6
import asyncio
import aiohttp
async def get_text(url):
# 獲取響應(yīng)內(nèi)容是異步操作, 使用await來獲取結(jié)果
response = await aiohttp.request('GET', url)
# 獲取網(wǎng)頁內(nèi)容也是異步操作
r = await response.text()
print(r)
loop = asyncio.get_event_loop()
# 如果需要執(zhí)行的對(duì)象有很多個(gè),將它們組成可迭代的對(duì)象(如列表),然后傳進(jìn)asyncio.wait()或asyncio.gather()
loop.run_until_complete(get_text("http://www.baidu.com"))
loop.close()
as_completed()
傳遞由Future對(duì)象構(gòu)成的可迭代對(duì)象式散,返回生成結(jié)果的Future對(duì)象(iterator)
舉個(gè)粟子
#!/usr/bin/env python3.6
import asyncio
import aiohttp
urls = ["http://www.baidu.com", "http://www.zhihu.com"]
async def get_text(url):
response = await aiohttp.request('GET', url)
r = await response.text()
print(r)
async def coro():
fututes = [get_text(url) for url in urls]
to_do_iter = asyncio.as_completed(fututes)
for future in to_do_iter:
try:
# 使用await獲取結(jié)果筋遭,而不是future.result()
res = await future
except FetchError as exe:
pass
loop = asyncio.get_event_loop()
loop.run_until_complete(coro())
loop.close()
文件io操作是阻塞型的,應(yīng)該要使用異步操作替代
asyncio在背后維護(hù)著一個(gè)ThreadPoolExecutor對(duì)象暴拄,我們可以調(diào)用 run_in_executor方法漓滔,將文件io操作交給他執(zhí)行
例子
def save_file(filename, content):
with open(filename, "w") as f:
f.write(content)
loop = asyncio.get_event_loop()
# 第一個(gè)參數(shù)是Executor實(shí)例,如果為None乖篷,則使用ThreadPoolExecutor默認(rèn)的實(shí)例
loop.run_in_exector(None, save_file, filename, content)