1. 程式人生 > >一個有趣的小例子,帶你入門協程模塊-asyncio

一個有趣的小例子,帶你入門協程模塊-asyncio

其他 until res .html pychar port 打印 換行 異步

一個有趣的小例子,帶你入門協程模塊-asyncio

上篇文章寫了關於yield from的用法,簡單的了解異步模式,【https://www.cnblogs.com/c-x-a/p/10106031.html】這次讓我們通過一個有趣例子帶大家了解asyncio基本使用。

目標效果圖

技術分享圖片

基本原理

1.通過不停的依次順序叠代"|/-"中的一個字符。
2.每次輸出前使用退格符模擬一個動態效果。所謂的退格符就是刪除上一個字符串,並在原來的位置輸出新的字符串。
代碼實現:

  1 import  itertools
  2 import sys
  3 import time
  4 flush=sys.stdout.flush
  5 for i in  itertools.cycle("|/-\\"):
  6      print(‘\b‘*len(i)+i,end=‘‘)
  7      flush()
  8      time.sleep(.1)

代碼解釋

1,2,3行導入需要的包。

4行定義7行調用,強制刷新緩存。
當我們打印一些字符時,並不是調用print函數後就立即打印的。
一般會先將字符送到緩沖區,然後再打印。這就存在一個問題,
如果你想等時間間隔的打印一些字符,
但由於緩沖區沒滿,不會打印。就需要采取強制刷新等手段了。

5行,使用itertools.cycle無窮的叠代括號內的字符串。

6行,print默認是print(end=‘\n‘),這裏修改其默認方法end=‘‘,不換行。
關鍵作用的是‘\b‘,‘\b‘*len(i)表示多次退格,長度由叠代的字符的個數決定。
8行 模擬休眠0.1秒。
這裏只是一個簡單的效果演示,下面我們使用一個使用協程的例子。

使用asyncio完成同樣的功能

該例子參考流暢的python,我對其作了部分修改。先看代碼,後面再做解釋。

# -*- coding: utf-8 -*-
# @Time : 2018/12/19 9:08 PM
# @Author : cxa
# @File : 18-2.py
# @Software: PyCharm
# 通過協程以動畫形式顯示文本式旋轉指針
import asyncio
import itertools
import sys
import time
async def spin(msg):  # (1)
    write, flush = sys.stdout.write, sys.stdout.flush  # (2)
    for char in itertools.cycle(‘|/-\\‘):  #(3) 
        status = char + ‘ ‘ + msg
        print(status, end=‘‘)
        flush()  #(4) 
        # write(‘\b‘ * len(status))  # (5) 
        print(‘\b‘ * len(status), end=‘‘)  # (6) 
        try:
            await asyncio.sleep(.1)  # (7) 
        except asyncio.CancelledError: # (8) 
            break
    # write(" " * len(status) + ‘\b‘ * len(status))  # (9) 
    print(" " * len(status) + ‘\b‘ * len(status), end=‘‘) # (10)


async def slow_function():
    # 假裝等待io一段時間
    await asyncio.sleep(3)
    return "very good!"


async def supervisor():
    # loop = asyncio.get_event_loop() # (11)
    # spinner = loop.create_task(spin(‘thking!‘)) # (12)
    spinner = asyncio.ensure_future(spin(‘thking!‘))  # (13)
    print(‘spinner object:‘, spinner) # (14)
    result = await slow_function()  # (15)
    spinner.cancel()   # (16)
    return result


def main():
    loop = asyncio.get_event_loop()  # (17)
    result = loop.run_until_complete(supervisor())  # (18)
    loop.close()# (19)
    print("Result:", result)


if __name__ == ‘__main__‘:
    main()

下面對上面編號進行一一講解。
首先導入必須的包,其中asyncio就是我們要使用的協程包。
(1)def代表一個函數或者方法,如果在前面加async def這個就變成協程了。不再是一個方法。
在python3.4的時候通過使用@asyncio.coroutine來修飾一個函數使其變為一個協程。現在不推薦使用。

(2) 定義對象方便後面使用。

(3)itertools.cycle會把一個可叠代對象無限重復下去。

(4)強制刷新緩存

(5)(6)這兩個是等價的:
當我們在使用print的時候,實際上是調用了 sys.stdout.write(obj+‘\n‘),print在打印時會自動加個換行符。
這裏就是一開始說的使用指定字符串長度的退格符

(7)我們使用asyncio.sleep函數來模擬IO操作。

(8)執行(16)的時候觸發。

(9)(10)這兩個是等價的,輸出最後的顯示結果。

(11)(12)這兩句可以用(13)來替代使用asyncio.ensure_future(coroutine)
和 loop.create_task(coroutine)都可以創建一個task。

(14) 輸出的是一個協程對象

(15)使用await把控制權交給主循環,以便loop調用其他的協程。

(16)Task對象可以取消,取消後會在協程當前暫停的yield處拋出asyncio.CancelledError異常。

(17)(18) asyncio.get_event_loop方法可以創建一個事件循環,
然後使用run_until_complete將協程註冊到事件循環,並啟動事件循環。協程的返回值是這次調用的返回值。

(19)結束循環。

參考資料:

流暢的python 第16章

關於asyncio的後續的一些使用請關註公眾號:python學習開發。

一個有趣的小例子,帶你入門協程模塊-asyncio