You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

discord.py开发答题机器人如何创建独立stop命令终止运行中的会话循环

实现方案

核心思路是用全局状态存储跨命令共享答题会话的运行状态,同时支持异步场景下的终止信号传递,具体修改如下:

1. 定义全局会话存储

在所有命令外层添加全局变量,用于记录活跃的答题会话,支持多用户/多频道同时答题互不干扰:

import asyncio
import random

# 存储活跃答题会话:键为 (发起用户ID, 频道ID),值为终止信号事件
active_quizzes = {}

2. 修改ask命令逻辑

添加会话注册、终止信号判断逻辑,替换原来的内部running函数:

@client.command()
async def ask(ctx):
    session_key = (ctx.author.id, ctx.channel.id)
    # 避免同一个用户在同一个频道重复发起答题
    if session_key in active_quizzes:
        await ctx.send("你已经有一个正在进行的答题会话了哦")
        return
    
    # 注册当前会话,创建终止事件
    stop_event = asyncio.Event()
    active_quizzes[session_key] = stop_event

    quiz_data = {
        'question_1': (["1", "one"], "one"),
        'question_2': (["2", "two"], "two"),
    }
    question = random.choice(list(quiz_data.keys()))
    answers, hint = quiz_data[question]

    await ctx.send("What is the answer to this question?")
    await asyncio.sleep(1)
    await ctx.send(question)

    def check_msg(msg):
        # 消息校验同时判断是否触发了终止信号
        return (msg.author == ctx.author 
                and msg.channel == ctx.channel
                and not stop_event.is_set())

    def check_answer(msg):
        return any(answer in msg.content.lower() for answer in answers)
    
    try:
        async with asyncio.timeout(10):
            while not stop_event.is_set():
                msg = await client.wait_for('message', check=check_msg)
                if check_answer(msg):
                    await ctx.send("good")
                    break
                else:
                    print('someone got it wrong lol')
    except asyncio.TimeoutError:
        # 超时后先判断是否已经被手动终止
        if stop_event.is_set():
            del active_quizzes[session_key]
            return
        await ctx.send(f"What is the answer to this question? hint: {hint}")
        await ctx.send(question)

        try:
            msg = await client.wait_for('message', check=check_msg, timeout=10)
            if check_answer(msg):
                await ctx.send("good")
            else:
                await ctx.send("wrong.")
        except asyncio.TimeoutError:
            await ctx.send("答题超时,本次会话结束")
    finally:
        # 所有场景结束后清理会话记录
        if session_key in active_quizzes:
            del active_quizzes[session_key]

3. 重写stopg命令逻辑

现在可以直接从全局存储中读取会话状态,触发终止信号:

@client.command()
async def stopg(ctx):
    session_key = (ctx.author.id, ctx.channel.id)
    if session_key in active_quizzes:
        # 触发终止信号
        active_quizzes[session_key].set()
        await ctx.send("Round is stopping...")
    else:
        await ctx.send("No round active")

方案说明

  • 用asyncio.Event作为终止信号,适配异步场景下的等待逻辑,不需要反复轮询状态
  • 基于用户ID+频道ID做会话隔离,支持多用户同时答题互不影响
  • finally块保证无论会话是正常结束、超时还是手动终止,都会清理状态,不会出现残留的无效会话
  • 如果你的机器人只需要单频道单场答题,也可以简化为单个全局布尔变量作为运行状态标识,逻辑更简单

内容的提问来源于stack exchange,提问作者Mario Arquette

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.14 00:42:04