需要等待同步函数中的函数

2024-09-21 05:33:53 发布

您现在位置:Python中文网/ 问答频道 /正文

我已经尝试解决这个问题两天了,读了StackOverflow中的50个问题和很多关于Python的文档。我不知道还能尝试什么

我的代码

import discord
import re
from datetime import datetime
import mysql.connector
from discord.ext import commands, tasks
from discord.utils import get
import atexit
from pynput import keyboard
import asyncio
from asgiref.sync import async_to_sync, sync_to_async

# The currently active modifiers
current = set()

# The key combination to check
COMBINATIONS_MUTE = [
    {keyboard.Key.shift, keyboard.KeyCode(char='a')},
    {keyboard.Key.shift, keyboard.KeyCode(char='A')}
]


COMBINATIONS_UNMUTE = [
    {keyboard.Key.shift, keyboard.KeyCode(char='b')},
    {keyboard.Key.shift, keyboard.KeyCode(char='B')}
]



GUILD_ID=guild_id
CHANNELS = ""
GUILD = ""
VOICE_CHANNEL = ""

client = commands.Bot(command_prefix = ".")

def get_channel(name):
    global CHANNELS
    for channel in CHANNELS:
        if (channel.name == name) and (channel.type.name == "voice"):
            return channel
    return False

def get_voice_channels():
    global CHANNELS
    channels = []
    for channel in CHANNELS:
        if (channel.type.name == "voice"):
            channels.append(channel)
    return channels

async def mute_all():
    global VOICE_CHANNELS
    print("mute all")
    for channel in VOICE_CHANNELS:
        for member in channel.members:
            await member.edit(mute=True)

async def unmute_all():
    global VOICE_CHANNELS
    print("unmute all")
    for channel in VOICE_CHANNELS:
        for member in channel.members:
            await member.edit(mute=False)


def on_press(key):
    if any([key in COMBO for COMBO in COMBINATIONS_MUTE]) and not key in current:
        current.add(key)
        if any(all(k in current for k in COMBO) for COMBO in COMBINATIONS_MUTE):
            asyncio.run(mute_all())
    elif any([key in COMBO for COMBO in COMBINATIONS_UNMUTE]):
        current.add(key)
        if any(all(k in current for k in COMBO) for COMBO in COMBINATIONS_UNMUTE):
            asyncio.run(unmute_all())

def on_release(key):
    if any([key in COMBO for COMBO in COMBINATIONS_MUTE]):
        current.remove(key)
    elif any([key in COMBO for COMBO in COMBINATIONS_UNMUTE]):
        current.remove(key)


@client.event
async def on_ready():
    global GUILD
    global CHANNELS
    global VOICE_CHANNELS
    global GUILD_ID

    GUILD = client.get_guild(GUILD_ID)

    CHANNELS = GUILD.channels

    VOICE_CHANNELS = get_voice_channels()
    print("bot ready")
    loop = asyncio.get_event_loop()
    with keyboard.Listener(on_press=on_press, on_release=on_release) as listener:
        listener.join()

client.run('token')

基本上它应该做的是:

  1. 当我按下Shift+A时,每个语音频道中的每个人都会静音
  2. 当我按下Shitf+B时,取消每个语音频道中的所有人的静音

问题是我需要等待member.edit(),但我不能,因为我不能等待mute_all(),也不能等待unmute_all(),因为on_press(key)不是异步的,我不能使它异步,因为键盘侦听器不允许我

我所尝试的(没有成功)

  1. member.edit()上使用asyncio.run()
  2. mute_all()上使用asyncio.run()
  3. 使on_press(key)异步
  4. member.edit()上使用async_to_sync()
  5. mute_all()上使用async_to_sync()

我不知道还能尝试什么


Tags: keyinimportforasynconchannelcurrent
3条回答

如果有事件循环,可以使用^{}调用异步函数

discord.py有一个可以使用的事件循环,即^{}

def on_press(key):
    if any([key in COMBO for COMBO in COMBINATIONS_MUTE]) and not key in current:
        current.add(key)
        if any(all(k in current for k in COMBO) for COMBO in COMBINATIONS_MUTE):
            client.loop.create_task(mute_all())
    elif any([key in COMBO for COMBO in COMBINATIONS_UNMUTE]):
        current.add(key)
        if any(all(k in current for k in COMBO) for COMBO in COMBINATIONS_UNMUTE):
            client.loop.create_task(unmute_all())

Listener不是异步的,因此它将阻止on_ready中的事件循环,您需要在执行器中初始化侦听器,在这种情况下,我们可以使用默认的侦听器

以下是我为使这一部分正常工作所做的全部更改:

def keyboard_listener():
    with keyboard.Listener(on_press=on_press, on_release=on_release) as listener:
        listener.join()

@client.event
async def on_ready():
    global GUILD
    global CHANNELS
    global VOICE_CHANNELS
    global GUILD_ID

    GUILD = client.get_guild(GUILD_ID)

    CHANNELS = GUILD.channels

    VOICE_CHANNELS = get_voice_channels()
    print("bot ready")

    loop.run_in_executor(None, keyboard_listener)


loop = asyncio.get_event_loop()

然后我用loop.create_task替换了所有的asyncio.run

如果我的指示不清楚,我有一个有效的版本,请随时提问

从一个异步到另一个同步再到异步是相当糟糕的,但是它可以工作,所以我想它不是愚蠢的

我还稍微更改了mute_allunmute_all,因为当前的实现只会在bot最初连接时影响通道中的语音用户。以下是我的更改示例:

async def mute_all():
    print("mute all")
    for channel in client.get_guild(GUILD_ID).channels:
        if not channel.type.name == "voice":
            continue
        for member in channel.members:
            await member.edit(mute=True)

试试这两个

#1st Way
loop = asyncio.get_event_loop()
loop.run_until_complete(async_function())

#2nd Way
asyncio.run_coroutine_threadsafe(async_function(), client.loop)

相关问题 更多 >

    热门问题