上篇文章寫了關於yield from的用法,簡單的瞭解非同步模式,【上次的內容連結】這次讓我們通過一個有趣例子帶大家瞭解asyncio基本使用。
上篇文章寫了關於yield from的用法,簡單的瞭解非同步模式,【上次的內容連結】這次讓我們通過一個有趣例子帶大家瞭解asyncio基本使用。
目標效果圖
在控制檯中顯示一個由ASCII字元"|/-\"構成的動畫旋轉指標.
基本原理
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.每次輸出前使用退格符模擬一個動態效果。所謂的退格符就是刪除上一個字串,並在原來的位置輸出新的字串。
程式碼實現:
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秒。
這裡只是一個簡單的效果演示,下面我們使用一個使用協程的例子。
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,我對其作了部分修改。先看程式碼,後面再做解釋。
# -*- 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學習開發。
流暢的python 第16章
關於asyncio的後續的一些使用請關注公眾號:python學習開發。