溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Python中怎么利用Asyncio實現(xiàn)異步編程

發(fā)布時間:2021-07-10 15:59:12 來源:億速云 閱讀:137 作者:Leah 欄目:編程語言

本篇文章為大家展示了Python中怎么利用Asyncio實現(xiàn)異步編程,內(nèi)容簡明扼要并且容易理解,絕對能使你眼前一亮,通過這篇文章的詳細介紹希望你能有所收獲。

異步是怎么一回事?

在傳統(tǒng)的順序編程中, 所有發(fā)送給解釋器的指令會一條條被執(zhí)行。此類代碼的輸出容易顯現(xiàn)和預(yù)測。 但是…

譬如說你有一個腳本向3個不同服務(wù)器請求數(shù)據(jù)。  有時,誰知什么原因,發(fā)送給其中一個服務(wù)器的請求可能意外地執(zhí)行了很長時間。想象一下從第二個服務(wù)器獲取數(shù)據(jù)用了10秒鐘。在你等待的時候,整個腳本實際上什么也沒干。如果你可以寫一個腳本可以不去等待第二個請求而是僅僅跳過它,然后開始執(zhí)行第三個請求,然后回到第二個請求,執(zhí)行之前離開的位置會怎么樣呢。就是這樣。你通過切換任務(wù)最小化了空轉(zhuǎn)時間。盡管如此,當(dāng)你需要一個幾乎沒有I/O的簡單腳本時,你不想用異步代碼。

還有一件重要的事情要提,所有代碼在一個線程中運行。所以如果你想讓程序的一部分在后臺執(zhí)行同時干一些其他事情,那是不可能的。

準(zhǔn)備開始

這是 asyncio 主概念最基本的定義:

  • 協(xié)程 — 消費數(shù)據(jù)的生成器,但是不生成數(shù)據(jù)。Python 2.5 介紹了一種新的語法讓發(fā)送數(shù)據(jù)到生成器成為可能。我推薦查閱David Beazley “A  Curious Course on Coroutines and Concurrency” 關(guān)于協(xié)程的詳細介紹。

  • 任務(wù) — 協(xié)程調(diào)度器。如果你觀察下面的代碼,你會發(fā)現(xiàn)它只是讓 event_loop 盡快調(diào)用它的_step ,同時 _step  只是調(diào)用協(xié)程的下一步。

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)
  • 事件循環(huán) — 把它想成 asyncio 的中心執(zhí)行器。

現(xiàn)在我們看一下所有這些如何融為一體。正如我之前提到的,異步代碼在一個線程中運行。

Python中怎么利用Asyncio實現(xiàn)異步編程

從上圖可知:

1.消息循環(huán)是在線程中執(zhí)行

2.從隊列中取得任務(wù)

3.每個任務(wù)在協(xié)程中執(zhí)行下一步動作

4.如果在一個協(xié)程中調(diào)用另一個協(xié)程(await  <coroutine_name>),會觸發(fā)上下文切換,掛起當(dāng)前協(xié)程,并保存現(xiàn)場環(huán)境(變量,狀態(tài)),然后載入被調(diào)用協(xié)程

5.如果協(xié)程的執(zhí)行到阻塞部分(阻塞I/O,Sleep),當(dāng)前協(xié)程會掛起,并將控制權(quán)返回到線程的消息循環(huán)中,然后消息循環(huán)繼續(xù)從隊列中執(zhí)行下一個任務(wù)...以此類推

6.隊列中的所有任務(wù)執(zhí)行完畢后,消息循環(huán)返回***個任務(wù)

異步和同步的代碼對比

現(xiàn)在我們實際驗證異步模式的切實有效,我會比較兩段 python 腳本,這兩個腳本除了sleep 方法外,其余部分完全相同。在***個腳本里,我會用標(biāo)準(zhǔn)的  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

上述內(nèi)容就是Python中怎么利用Asyncio實現(xiàn)異步編程,你們學(xué)到知識或技能了嗎?如果還想學(xué)到更多技能或者豐富自己的知識儲備,歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI