使用 asyncio 运行协程后如何继续原始事件循环?
Posted
技术标签:
【中文标题】使用 asyncio 运行协程后如何继续原始事件循环?【英文标题】:How do you continue with the original event loop after running a coroutine using asyncio? 【发布时间】:2021-05-19 08:39:15 【问题描述】:我正在创建一个 python 脚本,它基本上从网页中检索信息并将消息发送到不和谐服务器。
我有一个主要的文件
import asyncio
import discord
from dotenv import load_dotenv
def update(message:str):
load_dotenv()
TOKEN = os.getenv('DISCORD_TOKEN')
GUILD = os.getenv('DISCORD_GUILD')
client = discord.Client()
@client.event
async def on_ready():
for guild in client.guilds:
if guild.name == GUILD:
break
print(
f'client.user is connected to the following guild:\n'
f'guild.name(id: guild.id)'
)
updatesChannel = client.get_channel([CHANNEL 1 ID HERE])
await updatesChannel.send(message)
client.run(TOKEN)
def log(message:str):
load_dotenv()
TOKEN = os.getenv('DISCORD_TOKEN')
GUILD = os.getenv('DISCORD_GUILD')
client = discord.Client()
@client.event
async def on_ready():
for guild in client.guilds:
if guild.name == GUILD:
break
print(
f'client.user is connected to the following guild:\n'
f'guild.name(id: guild.id)'
)
serverLogChannel = client.get_channel([CHANNEL 2 ID HERE])
await serverLogChannel.send(message)
client.run(TOKEN)
while True:
text = ['Text1', 'Text2']
channel1text = text[0]
channel2text = text[1]
loop = asyncio.get_event_loop()
loop.run_until_complete( update(channel1text) )
loop = asyncio.get_event_loop()
loop.run_until_complete( log(channel2text) )
目前,脚本只会在第一个通道上发送消息,而不会在第二个通道上发送消息,并且不会继续进行 While 循环。我在这里遗漏了什么吗?
【问题讨论】:
client.get_channel(Channel)
应该如何在一个函数中返回 updatesChannel
而在另一个函数中返回 serverLogChannel
?你在哪里定义Channel
?
抱歉,Channel 只是频道 ID 的占位符,它是硬编码的。将更新问题以使其更清楚。谢谢
另外,update
和 log
是要一个接一个地运行还是并行运行?
一个接一个
它们是连接到相同的令牌/公会/...,正如这里所暗示的,还是连接到不同的?
【参考方案1】:
您的代码的核心问题是client.run
是一个方便的同步函数,它将运行事件循环并永远运行它,以保持客户端运行。这也是为什么您的 update
函数永远不会返回的原因。顺便说一句,将同步函数传递给run_until_complete
是行不通的,如果update
确实返回,你会得到一个异常,Python 不会继续下一行。
要解决此问题,您可以从 client.run
切换到 client.start
,这是异步的。您还可以利用两个客户端都连接到同一个令牌/公会并仅使用一个客户端这一事实。这样公会的搜索只能完成一次,log
和update
函数可以简化为简单的channel.send
。例如(未经测试):
async def send_message(client, channel_id, message):
channel = client.get_channel(channel_id)
await channel.send(message)
async def main():
load_dotenv()
TOKEN = os.getenv('DISCORD_TOKEN')
GUILD = os.getenv('DISCORD_GUILD')
client = discord.Client()
asyncio.create_task(client.start(TOKEN))
await client.wait_until_ready()
for guild in client.guilds:
if guild.name == GUILD:
break
print(
f'client.user is connected to the following guild:\n'
f'guild.name(id: guild.id)'
)
while True:
text = ['Text1', 'Text2']
channel1text = text[0]
channel2text = text[1]
await send_message(client, [CHANNEL 1 ID], channel1text)
await send_message(client, [CHANNEL 2 ID], channel2text)
if __name__ == '__main__':
asyncio.run(main())
【讨论】:
以上是关于使用 asyncio 运行协程后如何继续原始事件循环?的主要内容,如果未能解决你的问题,请参考以下文章