如何同时获取多个频道的历史记录?
How to fetch multiple channel histories concurrently?
所以我正在尝试为我的 Discord 机器人发出命令,它将检查服务器中的每个频道并检查每个频道中的最后一条消息,然后发送以 [=11 开头的所有频道=]变量。
async def starthistory(self, ctx, key, msg, num):
for channel in ctx.guild.text_channels:
async for message in channel.history(limit=1):
message_content = message.content.lower()
if len(message.embeds) > 0:
if len(message.embeds[0].title) > 0:
message_content = message.embeds[0].title.lower()
elif len(message.embeds[0].author) > 0:
message_content = message.embeds[0].author.lower()
elif len(message.embeds[0].description) > 0:
message_content = message.embeds[0].description.lower()
if message_content.startswith(key.lower()):
num += 1
msg += f"\n**{num}.** {channel.mention} - **{channel.name}**"
#startswith
@_list.command(name="starts_with",
aliases=["startswith", "sw", "s"],
brief="Lists all channels with message starting with <key>.",
help="Lists all channels with last message starting with the word/phrase <key>.",
case_insensitive=True)
async def _starts_with(self, ctx, *, key):
msg = f"Channels with last message starting with `{key}`:"
num = 0
wait = await ctx.send(f"Looking for messages starting with `{key}`...")
asyncio.create_task(self.starthistory(ctx=ctx, key=key, msg=msg, num=num))
if num == 0:
msg += "\n**None**"
msg += f"\n\nTotal number of channels = **{num}**"
for para in textwrap.wrap(msg, 2000, expand_tabs=False, replace_whitespace=False, fix_sentence_endings=False, break_long_words=False, drop_whitespace=False, break_on_hyphens=False, max_lines=None):
await ctx.send(para)
await asyncio.sleep(0.5)
await wait.edit(content="✅ Done.")
我希望它同时查看每个频道的历史记录,这样就不会花那么长时间。目前,我的代码不会更改已定义的变量:num
始终为 0 并且 msg
始终为 None
.
如何同时查看每个通道的历史记录而不是一次查看一个?
asyncio.create_task(coro)
创建一个异步任务并 运行 在后台运行它。要允许您的 for
循环异步地 运行,同时处理所有文本通道,您应该改用 asyncio.gather(coros)
。
这是工作代码(我将您的代码精简为仅相关部分):
@staticmethod
async def check_history(msgs, channel, key, semaphore):
async with semaphore:
async for message in channel.history(limit=1):
message_content = message.content.lower()
# trimmed some code...
if message_content.startswith(key.lower()):
num = len(msgs)
msgs += [f"**{num}.** {channel.mention} - **{channel.name}**"]
@_list.command()
async def _starts_with(self, ctx, *, key):
msgs = [f"Channels with last message starting with `{key}`:"]
tasks = []
semaphore = asyncio.Semaphore(10)
for channel in ctx.guild.text_channels:
tasks += [self.check_history(msgs, channel, key, semaphore)]
await asyncio.gather(*tasks)
if len(msgs) == 1:
msgs += ["**None**"]
msgs += [f"\nTotal number of channels = **{len(msgs)}**"]
msg = "\n".join(msgs)
print(msg)
note/why这个作品的要点:
- 我使用
asyncio.gather()
等待所有 check_history
协程。
- 我使用了
asyncio.Semaphore(10)
将最大并发数限制为 10。Discord API 不喜欢同时发送太多请求。频道太多,您可能会暂时被屏蔽。
- 通常,不建议将不可变对象(strs 和 ints)传递给外部函数并尝试更改其值。对于您的用例,我认为最好的选择是使用 msg 列表,然后
str.join()
稍后再使用。这也摆脱了 num
。
所以我正在尝试为我的 Discord 机器人发出命令,它将检查服务器中的每个频道并检查每个频道中的最后一条消息,然后发送以 [=11 开头的所有频道=]变量。
async def starthistory(self, ctx, key, msg, num):
for channel in ctx.guild.text_channels:
async for message in channel.history(limit=1):
message_content = message.content.lower()
if len(message.embeds) > 0:
if len(message.embeds[0].title) > 0:
message_content = message.embeds[0].title.lower()
elif len(message.embeds[0].author) > 0:
message_content = message.embeds[0].author.lower()
elif len(message.embeds[0].description) > 0:
message_content = message.embeds[0].description.lower()
if message_content.startswith(key.lower()):
num += 1
msg += f"\n**{num}.** {channel.mention} - **{channel.name}**"
#startswith
@_list.command(name="starts_with",
aliases=["startswith", "sw", "s"],
brief="Lists all channels with message starting with <key>.",
help="Lists all channels with last message starting with the word/phrase <key>.",
case_insensitive=True)
async def _starts_with(self, ctx, *, key):
msg = f"Channels with last message starting with `{key}`:"
num = 0
wait = await ctx.send(f"Looking for messages starting with `{key}`...")
asyncio.create_task(self.starthistory(ctx=ctx, key=key, msg=msg, num=num))
if num == 0:
msg += "\n**None**"
msg += f"\n\nTotal number of channels = **{num}**"
for para in textwrap.wrap(msg, 2000, expand_tabs=False, replace_whitespace=False, fix_sentence_endings=False, break_long_words=False, drop_whitespace=False, break_on_hyphens=False, max_lines=None):
await ctx.send(para)
await asyncio.sleep(0.5)
await wait.edit(content="✅ Done.")
我希望它同时查看每个频道的历史记录,这样就不会花那么长时间。目前,我的代码不会更改已定义的变量:num
始终为 0 并且 msg
始终为 None
.
如何同时查看每个通道的历史记录而不是一次查看一个?
asyncio.create_task(coro)
创建一个异步任务并 运行 在后台运行它。要允许您的 for
循环异步地 运行,同时处理所有文本通道,您应该改用 asyncio.gather(coros)
。
这是工作代码(我将您的代码精简为仅相关部分):
@staticmethod
async def check_history(msgs, channel, key, semaphore):
async with semaphore:
async for message in channel.history(limit=1):
message_content = message.content.lower()
# trimmed some code...
if message_content.startswith(key.lower()):
num = len(msgs)
msgs += [f"**{num}.** {channel.mention} - **{channel.name}**"]
@_list.command()
async def _starts_with(self, ctx, *, key):
msgs = [f"Channels with last message starting with `{key}`:"]
tasks = []
semaphore = asyncio.Semaphore(10)
for channel in ctx.guild.text_channels:
tasks += [self.check_history(msgs, channel, key, semaphore)]
await asyncio.gather(*tasks)
if len(msgs) == 1:
msgs += ["**None**"]
msgs += [f"\nTotal number of channels = **{len(msgs)}**"]
msg = "\n".join(msgs)
print(msg)
note/why这个作品的要点:
- 我使用
asyncio.gather()
等待所有check_history
协程。 - 我使用了
asyncio.Semaphore(10)
将最大并发数限制为 10。Discord API 不喜欢同时发送太多请求。频道太多,您可能会暂时被屏蔽。 - 通常,不建议将不可变对象(strs 和 ints)传递给外部函数并尝试更改其值。对于您的用例,我认为最好的选择是使用 msg 列表,然后
str.join()
稍后再使用。这也摆脱了num
。