您好,登錄后才能下訂單哦!
本篇文章為大家展示了Python中怎么利用Asyncio實現異步編程,內容簡明扼要并且容易理解,絕對能使你眼前一亮,通過這篇文章的詳細介紹希望你能有所收獲。
異步是怎么一回事?
在傳統的順序編程中, 所有發送給解釋器的指令會一條條被執行。此類代碼的輸出容易顯現和預測。 但是…
譬如說你有一個腳本向3個不同服務器請求數據。 有時,誰知什么原因,發送給其中一個服務器的請求可能意外地執行了很長時間。想象一下從第二個服務器獲取數據用了10秒鐘。在你等待的時候,整個腳本實際上什么也沒干。如果你可以寫一個腳本可以不去等待第二個請求而是僅僅跳過它,然后開始執行第三個請求,然后回到第二個請求,執行之前離開的位置會怎么樣呢。就是這樣。你通過切換任務最小化了空轉時間。盡管如此,當你需要一個幾乎沒有I/O的簡單腳本時,你不想用異步代碼。
還有一件重要的事情要提,所有代碼在一個線程中運行。所以如果你想讓程序的一部分在后臺執行同時干一些其他事情,那是不可能的。
準備開始
這是 asyncio 主概念最基本的定義:
協程 — 消費數據的生成器,但是不生成數據。Python 2.5 介紹了一種新的語法讓發送數據到生成器成為可能。我推薦查閱David Beazley “A Curious Course on Coroutines and Concurrency” 關于協程的詳細介紹。
任務 — 協程調度器。如果你觀察下面的代碼,你會發現它只是讓 event_loop 盡快調用它的_step ,同時 _step 只是調用協程的下一步。
class Task(futures.Future): def __init__(self, coro, loop=None): super().__init__(loop=loop) ... self._loop.call_soon(self._step) def _step(self): ... try: ... result = next(self._coro) except StopIteration as exc: self.set_result(exc.value) except BaseException as exc: self.set_exception(exc) raise else: ... self._loop.call_soon(self._step)
事件循環 — 把它想成 asyncio 的中心執行器。
現在我們看一下所有這些如何融為一體。正如我之前提到的,異步代碼在一個線程中運行。
從上圖可知:
1.消息循環是在線程中執行
2.從隊列中取得任務
3.每個任務在協程中執行下一步動作
4.如果在一個協程中調用另一個協程(await <coroutine_name>),會觸發上下文切換,掛起當前協程,并保存現場環境(變量,狀態),然后載入被調用協程
5.如果協程的執行到阻塞部分(阻塞I/O,Sleep),當前協程會掛起,并將控制權返回到線程的消息循環中,然后消息循環繼續從隊列中執行下一個任務...以此類推
6.隊列中的所有任務執行完畢后,消息循環返回***個任務
異步和同步的代碼對比
現在我們實際驗證異步模式的切實有效,我會比較兩段 python 腳本,這兩個腳本除了sleep 方法外,其余部分完全相同。在***個腳本里,我會用標準的 time.sleep 方法,在第二個腳本里使用 asyncio.sleep 的異步方法。
這里使用 Sleep 是因為它是一個用來展示異步方法如何操作 I/O 的最簡單辦法。
使用同步 sleep 方法的代碼:
import asyncio import time from datetime import datetime async def custom_sleep(): print('SLEEP', datetime.now()) time.sleep(1) async def factorial(name, number): f = 1 for i in range(2, number+1): print('Task {}: Compute factorial({})'.format(name, i)) await custom_sleep() f *= i print('Task {}: factorial({}) is {}\n'.format(name, number, f)) start = time.time() loop = asyncio.get_event_loop() tasks = [ asyncio.ensure_future(factorial("A", 3)), asyncio.ensure_future(factorial("B", 4)), ] loop.run_until_complete(asyncio.wait(tasks)) loop.close() end = time.time() print("Total time: {}".format(end - start))
腳本輸出:
Task A: Compute factorial(2) SLEEP 2017-04-06 13:39:56.207479 Task A: Compute factorial(3) SLEEP 2017-04-06 13:39:57.210128 Task A: factorial(3) is 6 Task B: Compute factorial(2) SLEEP 2017-04-06 13:39:58.210778 Task B: Compute factorial(3) SLEEP 2017-04-06 13:39:59.212510 Task B: Compute factorial(4) SLEEP 2017-04-06 13:40:00.217308 Task B: factorial(4) is 24 Total time: 5.016386032104492
使用異步 Sleep 的代碼:
import asyncio import time from datetime import datetime async def custom_sleep(): print('SLEEP {}\n'.format(datetime.now())) await asyncio.sleep(1) async def factorial(name, number): f = 1 for i in range(2, number+1): print('Task {}: Compute factorial({})'.format(name, i)) await custom_sleep() f *= i print('Task {}: factorial({}) is {}\n'.format(name, number, f)) start = time.time() loop = asyncio.get_event_loop() tasks = [ asyncio.ensure_future(factorial("A", 3)), asyncio.ensure_future(factorial("B", 4)), ] loop.run_until_complete(asyncio.wait(tasks)) loop.close() end = time.time() print("Total time: {}".format(end - start))
腳本輸出:
Task A: Compute factorial(2) SLEEP 2017-04-06 13:44:40.648665 Task B: Compute factorial(2) SLEEP 2017-04-06 13:44:40.648859 Task A: Compute factorial(3) SLEEP 2017-04-06 13:44:41.649564 Task B: Compute factorial(3) SLEEP 2017-04-06 13:44:41.649943 Task A: factorial(3) is 6 Task B: Compute factorial(4) SLEEP 2017-04-06 13:44:42.651755 Task B: factorial(4) is 24 Total time: 3.008226156234741
上述內容就是Python中怎么利用Asyncio實現異步編程,你們學到知識或技能了嗎?如果還想學到更多技能或者豐富自己的知識儲備,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。