正在等待下载Python中的asyncio

2024-04-19 23:45:38 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在开发一个discord机器人,我正在尝试实现一个音乐播放器。我正在使用discord和youtube dl包。这是处理play命令的函数(它仍然是一个原型):

@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.')

以及下载到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])

我的意思是,当下载完成时,我仍然可以使用bot的其他功能。据我所知,wait语句说“暂停play()函数的执行,在我等待的时候做些别的事情。当下载到mp3完成时,继续”。但是,它似乎读取下载时发出的命令,但仅在下载完成后执行这些命令。如何使其在下载时执行命令


Tags: path函数命令urlplaysongyoutubeos
1条回答
网友
1楼 · 发布于 2024-04-19 23:45:38

As far as I understand the await statement says "Suspend the execution of the play() function, do something else while I'm waiting. When download_to_mp3 finishes, continue"

这正是它的工作原理,只要您遵循异步规则,最基本的规则是:在异步期间不要阻塞。因为YoutubeDL.download显然是一个阻塞函数(您不需要等待它),所以download_to_mp3的执行会暂停整个事件循环。仅仅是在download_to_mp3中没有await语句这一事实就提示您,该函数只是名义上的异步函数

修复它的正确方法是从YoutubeDL切换到同一类型的异步下载程序(如果存在的话)。如果这不是一个选项,或者如果需要快速修复,可以使用^{},它将在不同的线程中执行阻塞函数,并返回一个等待对象,该对象将暂停等待器,直到阻塞函数完成。例如:

@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 ...

相关问题 更多 >