【问题标题】:Multi-threading with Discord (scheduled job)Discord 的多线程(计划作业)
【发布时间】:2019-03-12 23:06:15
【问题描述】:

首先,道歉。我对 Python 很陌生。我来自 Java/C# 编码背景。我在很多方面都喜欢 Python 的简单性,但也发现一些标准很难确定。

例如,我成功地让 Discord Bot 运行。异步方法运行良好。但我想安排一个工作每(比如)30 分钟运行一次。但是,当我输入 asyncio.run(job()) 时,Python 告诉我“run”不是 asyncio 的属性。我真的不知道为什么会这么说。哎呀,asyncio 甚至是“正确”的方法吗?

不和谐导入是否可能以某种方式掩盖了它?我想我可能需要买一本书什么的!

再次感谢。我确实尝试过搜索,但没有任何结果!

【问题讨论】:

  • Asycio 不容易上手。我建议你先阅读this guide
  • 啊,所以也许我看到了我的问题。我需要得到一个“event_loop”,然后“运行”它。 “run_forever”会在后台运行并继续执行下一个命令吗?还是只会阻塞?如果可以释放它,我可以在我的代码中添加“睡眠”。
  • 你应该添加一些代码,这样我们就可以看到你在尝试什么。
  • asyncio.run 不是正确的做法,因为client.run 已经在discord.py 中启动了一个事件循环——一次只能有一个事件循环!
  • run 可能不是asyncio 的属性,因为它仅在 Python 3.7 中添加——您“运行”哪个 Python 版本? :-)

标签: python python-asyncio discord discord.py


【解决方案1】:

on_ready 在不和谐机器人启动时被调用,因此一种方法是将您的工作附加到它:

import discord
import asyncio

client = discord.Client()

@client.event
async def on_ready():
    while True:
        await asyncio.sleep(30*60)  # every 30 minutes
        job()

client.run(os.environ.get('DISCORD_BOT_SECRET'))  # provide your API token here!!

asyncio.sleep 是一种非阻塞 睡眠——如果在这里使用time.sleep,那么机器人将等待time.sleep 完成并且不会响应任何其他消息进来。但是await asyncio.sleep 所做的是将控制权交还给可以处理其他机器人功能的事件循环。只有在 30 分钟后控制权才会返回到on_ready

请注意,当您的作业运行时,它会阻止您的机器人,这对于任务时间超过几秒钟的作业来说是个问题。如果您的工作是基于 I/O 的(例如获取网站),您可以使用异步 I/O 操作(例如 aiohttp)来保持响应。如果您的作业是基于 CPU 的,您可能必须使用多个进程,例如 subprocess.Popen 如果您的作业可以使用终端命令调用。

【讨论】:

  • 对于多个作业:将每个作业创建为async def 函数(包括while True 循环)并在on_ready 中将每个作业作为任务启动一次!
【解决方案2】:

每 30 分钟安排一次作业的现代方法是使用discord.ext.tasks

import asyncio
import contextlib
import discord
from discord.ext import tasks

client = discord.Client()

@tasks.loop(minutes=30)  # every 30 minutes
async def job():
    with contextlib.suppress(Exception):
        ...  # your code here

job.start()
client.run(os.environ.get('DISCORD_BOT_SECRET'))  # provide your API token here!!

Discord 客户端的事件循环将每 30 分钟调用一次函数 job()。这里有几个注意事项:

  • 如果job() 抛出异常,则整个循环将停止。 没错,不仅仅是这个调用,整个循环都会退出。这就是为什么我添加了一个 with 语句来捕获所有异常,这相当于 try: ... except: pass
  • job() 运行时,你的机器人的其他部分被阻塞了。这是因为异步不是使用多线程实现的,而是在单线程中使用协程。解决此问题的方法可能是使您的代码异步(例如,使用aiohttp 处理网络请求)或使用subprocess.Popen 启动另一个进程。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-19
    • 2013-12-14
    • 1970-01-01
    • 2022-01-01
    • 2017-01-20
    相关资源
    最近更新 更多