我正在使用discord.py rewrite编写一个discord机器人,我想每天在特定时间运行一个函数。我完全没有异步函数的经验,并且我不知道如何在不使用“等待”的情况下运行一个异步函数。这只是我的代码的一部分,这就是为什么可能无法定义某些内容的原因。
async def send_channel():
try:
await active_channel.send('daily text here')
except Exception:
active_channel_id = None
active_channel = None
async def timer():
while True:
schedule.run_pending()
await asyncio.sleep(3)
schedule.every().day.at("21:57").do(await send_channel())
@bot.event
async def on_ready():
print("Logged in as")
print(bot.user.name)
print(bot.user.id)
print("------")
bot.loop.create_task(timer())
使用schedule.every().day.at("00:00").do()
函数,将await send_channel()
放在.do()
的参数中时出现此错误:
self.job_func = functools.partial(job_func,* args,** kwargs)TypeError:第一个参数必须是可调用的
但是当我不使用await且仅将send_channel()
作为参数时,出现此错误:
RuntimeWarning:从未等待协程'send_channel'
我不太擅长编程,所以如果有人可以尝试为我愚弄它,那就太好了。
谢谢
您正在做的事不起作用,因为do
接受了一个[[function(或另一个可调用),但是您正在尝试await
或调用一个函数,然后将结果传递给它。] >await send_channel()
会阻塞,直到发送完成,然后再给您None
,这不是功能。 send_channel()
返回一个协程,您可以稍后等待它做一些工作,它也不是函数。
如果仅通过send_channel
传递了它,那是一个函数,但它是ascynio
协程函数,schedule
不知道如何运行。
schedule
集成到asyncio
事件循环中,并弄清楚如何将异步作业包装为schedule
任务,反之亦然,等等,不如将schedule
]自己的线程。如何连续运行调度程序而不阻塞主线程?
在单独的线程中运行调度程序。 Mrwhick为此问题写了一个很好的解决方案here(寻找run_continuously())。基本思想很简单。将您的
timer
功能更改为此:
schedstop = threading.Event()
def timer():
while not schedstop.is_set():
schedule.run_pending()
time.sleep(3)
schedthread = threading.Thread(target=timer)
schedthread.start()
在程序开始前,甚至在开始asyncio
事件循环之前,请执行此操作。
在退出时,停止调度程序线程:
schedstop.set()
现在,要添加任务,无论您是在顶级代码中,在异步协程中还是在scheduler
任务中,都只需像这样添加即可:
schedule.every().day.at("21:57").do(task)
现在,回到您的第一个问题。您要运行的任务不是正常功能,它是asyncio
协程,它必须在主线程上作为主事件循环的一部分运行。
但是这正是call_soon_threadsafe
的目的。您要呼叫的是:
call_soon_threadsafe
要让bot.loop.call_soon_threadsafe(send_channel)
运行它,您只需传递scheduler
作为函数,并传递bot.loop.call_soon_threadsafe
作为参数。
所以,把它们放在一起:
send_channel
schedule.every().day.at("21:57").do(
bot.loop.call_soon_threadsafe, send_channel)
将协程安排到事件循环(而不是回调):run_coroutine_threadsafe
的AsyncIOScheduler,它与异步功能(例如asyncio.run_coroutine_threadsafe(async_function(), bot.loop)
)更自然地工作。就您而言,您可以简单地编写以下形式的内容: