Python從3.5版本開始加入了async和await關鍵字,讓我們可以用非同步的方式來編寫程式。非同步程式的好處是可以在等待IO操作時不會阻塞主執行緒,從而提高程式運行效率。
要使用async/await,我們需要先將函式宣告為async def,就可以在函式內使用await。await用在非同步函式呼叫前,會暫停執行直到呼叫完成,再繼續往下執行。舉例:
import asyncio
async def fetch_data():
print('start fetching')
await asyncio.sleep(2) # 模擬IO阻塞的操作
print('done fetching')
return {'data': 1}
async def print_number():
for i in range(10):
print(i)
await asyncio.sleep(0.25)
async def main():
task1 = asyncio.create_task(fetch_data()) # 建立task1
task2 = asyncio.create_task(print_number()) # 建立task2
print('start')
await task1 # 等待task1完成
print('continue')
await task2 # 等待task2完成
asyncio.run(main())
這個例子中,main函式使用await等待task1和task2完成。在等待時,主執行緒不會被block,可以去執行print和其他尚未await的程式碼。這同時也被稱為協程。
我們可以看到,非同步程式可以發揮Python的多執行緒效能,並避免執行緒間的鎖死問題。Asyncio模組提供了非同步IO和事件循環,是實作非同步程式的重要工具。
更多資訊可見 https://docs.python.org/zh-tw/3/library/asyncio.html。
同樣的在discord.py中也利用了asyncio來實現非阻塞的 asynchronous 事件循環。
Discord.py中的Bot是一個asyncio.Client,代表一個連線到Discord API的非同步客戶端。 我們可以透過discord.py來監聽事件並執行非同步函式,例如:
import discord
client = discord.Client()
@client.event
async def on_ready():
print('Logged in as')
print(client.user.name)
@client.event
async def on_message(message):
if message.content.startswith('!hello'):
await message.channel.send('Hello!')
await client.process_commands(message)
client.run('token')
在這裡,on_ready和on_message都是非同步函式,會與Discord API形成一個事件循環。
當Bot完成登入時,on_ready會被呼叫;當收到訊息時,on_message會被呼叫。 我們用await來呼叫非同步的API如send(),這樣Bot就可以持續接收其他事件,而不會被block住。
所以透過discord.py和asyncio,我們可以方便地用非同步的方式來開發Discord 機器人了。
因此我們也可以在discord.py程式中使用自己寫的協程函式如下:
utils.py
# utils.py
import asyncio
async def my_async_func():
await asyncio.sleep(1)
print('Done!')
# bot.py
import discord
from utils import my_async_func
client = discord.Client()
@client.event
async def on_ready():
print('Ready!')
@client.event
async def on_message(message):
if message.content == '!mycmd':
await my_async_func()
client.run('token')
在on_message事件中檢測指令並呼叫自定義的async函數
使用await來呼叫該函數,以非同步的方式執行
my_async_func會在背景執行,不會阻塞on_message繼續處理其他訊息
這樣就可以將自定義的async程式碼整合到discord.py機器人中,並發揮非阻塞異步編程的優勢了。