从不等待不和谐的Python机器人协同程序

2024-03-28 17:00:25 发布

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

我正在尝试用Python制作一个盲测试机器人游戏,它实际上运行得很好。我用play_next()函数在队列中获得了一个完整的spotify播放列表

def play_next(ctx):

    if len(song_queue) >= 1:
        del song_queue[0]
        source = song_queue[0]
        vc.play(FFmpegPCMAudio(source=source.preview_url),
            after=lambda e: play_next(ctx))
        track_played = source

@client.command()
async def start(ctx):
    ...
    ...
    for song in tracks:
        if not song.track.preview_url:
            continue
        source = song.track
        song_queue.append(source)
        if not vc.is_playing():
            vc.play(FFmpegPCMAudio(source=source.preview_url),
                after=lambda e: play_next(ctx))
            track_played = source

同样,前面的代码工作得很好,但是当我将play_next()函数转换为async以输出有关正在播放的曲目的详细信息时,问题就开始了

async def play_next(ctx):

    await ctx.send("The answer was: {} from {}".format(track_played.name,
        ' and'.join(track_played.artists)))
    if len(song_queue) >= 1:
        del song_queue[0]
        source = song_queue[0]
        await ctx.send('Next song is about to start')
        vc.play(FFmpegPCMAudio(source=source.preview_url),
            after=lambda e: play_next(ctx))
        track_played = source

运行前面的代码会引发以下错误:play_next() was never awaited。 现在我知道很多人都经历过这类问题,但我显然没有理解我在过去几个小时里读到的内容,我所做的任何尝试都无法解决这一问题。。。如果有人能真正启发我,那就太好了

编辑

我终于找到了一个解决方案,我真的不知道它是安全的还是良好的做法。 我必须使play_next()函数保持同步,并在另一个async函数中调用ctx.send(),如下所示:

async def sendMsg(message, ctx):
    await ctx.send(message)

并使用asyncio调用主循环线程中的协程。见:

def play_next(ctx):
    ...
    send_fut = asyncio.run_coroutine_threadsafe(sendMsg(message, ctx), loop)
    send_fut.result()
    if len(song_queue) >= 1:
        source = song_queue[0]
        message = ('Next song is about to start')
        send_fut = asyncio.run_coroutine_threadsafe(sendMsg(message, ctx), loop)
        send_fut.result()
        del song_queue[0]
        track_played = source
        vc.play(FFmpegPCMAudio(source=source.preview_url),
                after=lambda x: play_next(ctx))

之前使用全局变量初始化了main()中的loop。请注意,在找到正确的命令和位置之前,我在这两行中做了很多努力。请注意get_event_loop()而不是new_event_loop()

def main():
    global loop

    loop = asyncio.get_event_loop()
    asyncio.set_event_loop(loop)
    def_globals()
    client.run('TOKEN')

希望这可以帮助其他人


Tags: loopsendurlsourceplayifqueuesong