我正在做一个不和谐机器人,试图解决这个问题。我想知道如何在非异步函数或中使用await,如果我可以在lambda行(代码的最后一行)中等待函数。
我试过用玩家变量做asyncio.run
,我也试过asyncio.run_coroutine_threadsafe
,它不起作用。
关于如何使它工作有什么想法吗?
代码:
def queue_check(self, ctx):
global queue_list
global loop
global playing
if loop is True:
queue_list.append(playing)
elif loop is False:
playing = ''
if ctx.channel.last_message.content == '$skip' or '$s':
return
song = queue_list.pop(0)
player = await YTDLSource.from_url(song, loop=self.client.loop, stream=True)
ctx.voice_client.play(player, after= queue_check(self,ctx))
@commands.command(aliases=['p'])
@commands.guild_only()
async def play(self, ctx, *, url):
global queue_list
global playing
if ctx.voice_client is None:
if ctx.author.voice:
await ctx.author.voice.channel.connect()
else:
return await ctx.send("> You are not connected to a voice channel.")
async with ctx.typing():
player = await YTDLSource.from_url(url, loop=self.client.loop, stream=True)
await ctx.send(f'> :musical_note: Now playing: **{player.title}** ')
playing = url
await ctx.voice_client.play(player, after=lambda e: queue_check(self,ctx))
需要import asyncio
要实际运行协程,asyncio提供了三个主要机制:
- asyncio.run()函数运行顶级入口点" main() "函数(参见上面的例子) 等待协同程序。将打印下面的代码片段"hello"后等待1秒,然后打印"world"后等待2秒:
示例
import asyncio
import time
async def say_after(delay, what):
await asyncio.sleep(delay)
print(what)
async def main():
print(f"started at {time.strftime('%X')}")
await say_after(1, 'hello')
await say_after(2, 'world')
print(f"finished at {time.strftime('%X')}")
asyncio.run(main())
started at 17:14:32
hello
world
finished at 17:14:34
细节
我也是异步编程的新手,今天深入研究了一下。因此,不能在非异步函数中使用await
是一个非常严格的规则。
所以你不能这样做:
def foo(delay):
await asyncio.sleep(delay)
async必须与await配对。但是,您可以向事件循环添加任务。我只是想发送一条消息,所以我做了这样的事情:
def queue_check(self, ctx):
#some preceding code
#
#adding a function to the event loop
self.bot.loop.create_task(ctx.send("my message"))
当asyncio决定它有足够的资源时,它就发送该消息。然而,在你的情况下。因为你需要player
就在那里,这可能不合适。
如果我可以建议一个替代方法,而不是把字符串放在队列中:
song = queue_list.pop(0) #im confident song is a string
为什么不排队YTDLSource对象呢?
async def Q(self, ctx, url):
"""Add songs to Queue"""
player = await YTDLSource.from_url(url)
queue_list.append(player)
如果您确实需要(尽管不推荐),您可以从同步方法运行异步方法,而与实际循环运行的事实无关:
try:
asyncio.get_running_loop().run_until_complete(async_method())
except RuntimeError:
asyncio.run(async_method())