【问题标题】:Discord.py Bot Takes too Long to RespondDiscord.py Bot 响应时间过长
【发布时间】:2021-10-16 05:57:02
【问题描述】:

目标:

我正在开发一个不和谐机器人,它每 5 秒左右扫描一个网址,检查该网页上的指定更改,如果发生更改,将在不和谐频道中发送消息。我通过使用on_message 中的 if 语句将 url 发送到机器人来完成此操作。然后将该 url 传递给 tasks.loop() 函数,在另一个函数中对其进行扫描和处理以进行更改。

问题

我希望能够在 discord 频道中发送一条消息,该消息可以快速结束在 tasks.loop() 中发生的过程,这样我就可以使用 on_message 函数将其传递给不同的 url 以进行扫描。在目前的形式下,它可以工作——只是非常很慢。从发送取消触发器到发送进程已取消的验证消息大约需要 3 分钟。我需要做这个 5 秒或更短。值得一提的是,该机器人使用replituptime robot 继续运行,但我确信较长的响应时间与正常运行时间机器人唤醒repl 的频率无关。

代码:

我的代码要复杂得多,并且充斥着名称不明的变量,所以这里有一个更简单的 sn-p 代码,具有相同的一般结构。

client = discord.Client()
channel = client.get_channel(CHANNEL_ID)

@tasks.loop()
async def myloop(website, dataframe):
    
    channel = client.get_channel(CHANNEL_ID)
    
    try:
        # iteratively scrape data from a website for
        # a predefined change in the dataframe
        if change = True:
            await channel.send(notification)
            
    except:
        pass


@client.event
async def on_message(message):
    
    channel = client.get_channel(CHANNEL_ID)
    msg = message.content
    
    if msg.startswith('track'):
        
        website = msg[6:]
        await channel.send('Now tracking '+str(website))
        myloop(website,df)

    if msg.starswith('stop'):
        
        myloop.cancel()
        await channel.send('Done tracking, awaiting orders.')

        

尝试的解决方案:

我尝试过使用某些形式的线程,但我还很陌生,但我还没有找到让它工作得更快的方法。任何建议或解决方案将不胜感激!一段时间以来,我一直在网上寻找帮助。

【问题讨论】:

    标签: python asynchronous discord.py client repl.it


    【解决方案1】:

    看起来您可以使用 client.loop.create_task 创建 asyncio 任务对象,并使用它们的 cancel 方法在正确的时间立即取消这些 asyncio 任务,例如

    import asyncio
    from replit import db
    
    
    _task = None
    
    
    async def myloop():
        website = db['website']
        dataframe = db['dataframe']
        channel = client.get_channel(CHANNEL_ID)
    
        while not client.is_closed():
            await asyncio.sleep(5)
            try:
                # iteratively scrape data from a website for
                # a predefined change in the dataframe
                if change:
                    await channel.send(notification)
            except:
                pass
    
    
    @client.event
    async def on_message(message):
        global _task  # This gives the function access to the variable that was already created above.
        msg = message.content
        
        if msg.startswith('track'):
            website = msg[6:]
            await message.channel.send('Now tracking '+str(website))
            db['website'] = website
            db['dataframe'] = df
            if _task is not None:
                _task.cancel()
            _task = client.loop.create_task(myloop())
    
        if msg.startswith('stop'):
            if _task is not None:
                _task.cancel()
                _task = None
                await message.channel.send('Done tracking, awaiting orders.')
    
    

    create_task 采用的参数是一个不带参数的协程,因此该函数需要以不同的方式访问网站 URL 和数据框(我不确定您更喜欢或最好的方式;使用replit的db只是一个例子)。

    通过这种方法,您应该能够再次使用track 来更改正在监控的网站,而无需在两者之间使用stop

    文档中的更多详细信息:

    【讨论】:

    • 这似乎工作,但它仍然有一个错误。 _task 变量不在 on_message 事件的范围内,我通过添加 db['Task'] = None 并将每个 _task 实例替换为相同的 db['Task'] 引用来修复它。它似乎确实有效,但我在client.loop.create_task(myloop()) 行上收到一个很长的控制台错误,最终返回:ValueError: Circular reference detected。我对第一个 _task 热修复的解决方案搞砸了吗?
    • 我在上面的回答中修正了两个错误。我尝试运行代码并得到同样的错误。可以通过将db['Task'] 更改回_task 并将global _task 放在on_message 的顶部附近以使函数可以访问变量来修复它。另一个错误是将startswith 拼错为starswith。如果您继续需要更多的全局变量,您可能需要考虑子类化discord.Clientdiscord.Bot,这样您就可以将全局变量转换为类属性,并且以后不太可能出现更多错误。
    • 哦!我现在明白了。谢谢@wheelercj!快乐编码
    猜你喜欢
    • 2020-02-22
    • 2020-09-12
    • 2016-10-24
    • 2016-07-20
    • 2018-11-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-09
    相关资源
    最近更新 更多