我正在使用discord.py 创建一个discord 机器人,我需要每天在特定时间执行某些操作。我看到了这个答案:如何在discord.py rewrite中进行循环?到目前为止我一直在使用它。
当我在 heroku 免费计划上托管我的机器人时,问题就开始了。 Heroku 上的服务器每天至少重置一次,这会弄乱计时器,如该帖子所示。
我还看到了schedule图书馆。问题在于它似乎使用了无限循环。这不会阻止我在 24 小时内运行其他任何操作吗?除了每 24 小时发送一次消息之外,机器人还需要能够随时响应命令。
即使服务器重置,如何每天在特定时间执行操作?预先感谢您!
您可以编写一个函数在不同的线程上定期运行,并检查是否是发送消息的正确时间,如下例所示:
from datetime import datetime
import threading
def checkTime():
# This function runs periodically every 1 second
threading.Timer(1, checkTime).start()
now = datetime.now()
current_time = now.strftime("%H:%M:%S")
print("Current Time =", current_time)
if(current_time == '02:11:00'): # check if matches with the desired time
print('sending message')
checkTime()
我知道我迟到了,但这可能对未来的用户有帮助。
有一个名为
APScheduler
的库,可用于通过设置 cron 作业来运行函数(除了 cron 之外,还有其他方法。阅读更多)。
一个小例子如下:
import discord
from discord.ext import commands
from apscheduler.schedulers.asyncio import AsyncIOScheduler
from apscheduler.triggers.cron import CronTrigger
class Scheduler(commands.Cog):
"""Schedule commands."""
def __init__(self, bot):
self.bot = bot
# Initialize session
self.session = aiohttp.ClientSession()
# Scheduled events
async def schedule_func(self):
def schedule(self):
# Initialize scheduler
schedule_log = logging.getLogger("apscheduler")
schedule_log.setLevel(logging.WARNING)
job_defaults = {
"coalesce": True,
"max_instances": 5,
"misfire_grace_time": 15,
"replace_existing": True,
}
scheduler = AsyncIOScheduler(job_defaults = job_defaults,
logger = schedule_log)
# Add jobs to scheduler
scheduler.add_job(self.schedule_func, CronTrigger.from_crontab("0 * * * *"))
# Every hour
并在我们的
main.py
文件中添加此内容(显然是在导入 schedule_jobs.py
文件之后):
# Start scheduled commands
scheduler = schedule_jobs.Scheduler(bot).schedule()
scheduler.start()
heroku 免费计划是 Linux。因此,cron将让您在特定时间运行事物,而/etc/init.d/将让您在启动时运行事物。了解您的操作系统是一件好事。
您是否考虑过使用多线程来运行您的程序?您可以让一个线程等待您想要的时间,而另一个线程则运行程序的其余部分。 以下是一些可帮助您入门的文档:Python 线程简介、线程文档
您可以使用discord.ext.tasks:
import datetime
import pytz
from discord.ext import commands, tasks
time = datetime.time(hour=9, minute=40, tzinfo=pytz.timezone("Europe/Prague"))
class DailyAction(commands.Cog):
def __init__(self, bot) -> None:
self.bot = bot
self.my_task.start()
@tasks.loop(time=time)
async def my_task(self) -> None:
print("This should trigger everyday at 9:40 AM (CET)")
async def setup(bot) -> None:
await bot.add_cog(DailyAction(bot))
查看文档了解更多详细信息。
Heroku 也有自己的调度程序,此答案中的更多信息。
您可以有一个无限循环并使用 asyncio.sleep() 函数。这允许您从脚本中的任何位置处理命令并且仍然等待时间。这是一个小例子:
import asyncio
while True:
await asyncio.sleep(60)
print(1)
@client.command()
async def command(ctx):
pass
脚本每分钟都会打印 1,只要有人执行该命令,它就会执行。