等待在 Python 中使用 asyncio 下载
Posted
技术标签:
【中文标题】等待在 Python 中使用 asyncio 下载【英文标题】:Awaiting download with asyncio in Python 【发布时间】:2020-10-07 12:50:23 【问题描述】:我正在开发一个不和谐的机器人,我正在尝试实现一个音乐播放器。我正在使用 discord 和 youtube-dl 包。这是处理播放命令的函数(它仍然是一个原型):
@client.command(brief='Plays the song from the url.')
async def play(ctx, url):
voice = get(client.voice_clients, guild=ctx.guild)
if not voice.is_playing():
try:
if 'song.mp3' in os.listdir(curr_dir):
os.remove(os.path.join(curr_dir, 'song.mp3'))
await download_to_mp3(url)
voice.play(discord.FFmpegPCMAudio(os.path.join(curr_dir, 'song.mp3')))
voice.volume = 100
except youtube_dl.DownloadError:
await ctx.send('Invalid url.')
还有 download_to_mp3() 函数:
async def download_to_mp3(url):
opts =
'outtmpl': os.path.join(curr_dir, 'song.webm'),
'format': 'bestaudio/best',
'postprocessors': [
'key': 'FFmpegExtractAudio',
'preferredcodec': 'mp3',
'preferredquality': '192',
],
with youtube_dl.YoutubeDL(opts) as ydl:
ydl.download([url])
我的意思是它的工作方式是在下载完成时,我仍然可以使用机器人的其他功能。据我了解,等待语句说“暂停 play() 函数的执行,在我等待时做其他事情。当 download_to_mp3 完成时,继续”。但是,它似乎读取下载时发出的命令,但仅在下载完成后才执行它们。如何让它在下载时执行命令?
【问题讨论】:
【参考方案1】:据我了解,await 语句说“暂停 play() 函数的执行,在我等待时执行其他操作。当 download_to_mp3 完成时,继续”
这正是它的工作原理,前提是您遵循异步规则,基本规则是:在异步期间不要阻塞。由于YoutubeDL.download
显然是一个阻塞函数(你不需要等待它),download_to_mp3
的执行会停止整个事件循环。 download_to_mp3
中没有 await
语句这一事实会提示您该函数只是名称上的异步。
修复它的正确方法是从YoutubeDL
切换到同类型的异步下载器(如果存在)。如果这不是一个选项,或者如果您需要快速修复,您可以使用run_in_executor
,它将在不同的线程中执行一个阻塞函数,并返回一个可等待的对象,该对象挂起等待者,直到阻塞函数完成。例如:
@client.command(brief='Plays the song from the url.')
async def play(ctx, url):
voice = get(client.voice_clients, guild=ctx.guild)
if not voice.is_playing():
try:
if 'song.mp3' in os.listdir(curr_dir):
os.remove(os.path.join(curr_dir, 'song.mp3'))
loop = asyncio.get_event_loop()
await loop.run_in_executor(None, download_to_mp3, url)
voice.play(discord.FFmpegPCMAudio(
os.path.join(curr_dir, 'song.mp3')))
voice.volume = 100
except youtube_dl.DownloadError:
await ctx.send('Invalid url.')
# note: download_to_mp3 is now an ordinary function, not an async one
def download_to_mp3(url):
... the same definition as before ...
【讨论】:
工作得很好。谢谢!以上是关于等待在 Python 中使用 asyncio 下载的主要内容,如果未能解决你的问题,请参考以下文章
异步等待函数中的 Python asyncio.semaphore
Python asyncio - 使用Task的循环退出已被销毁,但它正在等待处理