【问题标题】:Run multiple coroutines at the same time in python [Discord.py]在python中同时运行多个协程[Discord.py]
【发布时间】:2021-04-26 02:47:36
【问题描述】:

我正在为我的朋友制作一个 discord 机器人,它会检查网站上是否有货,如果发现有货,则会向 discord 频道发送消息。我正在尝试同时运行 ne 和 bB 方法,并且彼此独立。当“await channel.send”行在各自的方法中运行时,我收到“超时上下文管理器应该在任务中使用”。此行应该 send 导致不和谐机器人向指定频道发送消息。否则它工作正常。我尝试按照不和谐文档将它们作为任务循环运行,但没有成功。我还研究了广泛的替代方法来实现相同的目标,但不断陷入死胡同。无论如何要在一个 .py 文件中实现这一点,还是我需要重写。诚然,我可能不明白线程或协程是如何工作的,但我自己也做了很多研究,现在正在寻求外部帮助。

这是我的代码。 (我已经审查了潜在的私人信息,例如不和谐频道 ID)


import time
import requests
import re
import discord
import threading
import random
import asyncio
from discord.ext import tasks


bbUrlList = []
neUrlList = []
neGpuList = []
neSkipList = {}

client = discord.Client()

with open("DiscordToken.txt",'r') as tokenFile:
    token = str(tokenFile.readline()).replace("Token=","")

with open("bb.txt",'r') as file:
        for line in file:
            bbUrlList.append(line.split(" ")[1])

with open("ne.txt",'r') as file:
        for line in file:
            neUrlList.append(line.split(" ")[1])
            neGpuList.append(line.split(" ")[0])

async def bB(channel):
    while True:
        for x in range(0,len(bbUrlList)):
            url = bbUrlList[x]
            headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.85 Safari/537.36'}
            request = requests.get(url, headers=headers)
            request.encoding = "utf-8"
            text = request.text
            if re.search("add to cart", text, re.IGNORECASE) or re.search("see details", text, re.IGNORECASE):
                await channel.send("Bb appears to be dropping NOW!")
                print("[POSSIBLE DROP] Link:", bbUrlList[x])
                time.sleep(1800)
            else:
                print("[OUT OF STOCK] Link:", bbUrlList[x])
                time.sleep(random.randint(1,3))

async def ne(channel):
    while True:
        for x in range(0,len(neUrlList)):
            url = neUrlList[x]
            gpu = neGpuList[x]
            headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.85 Safari/537.36'}
            request = requests.get(url, headers=headers)
            request.encoding = "utf-8"
            text = request.text
            if re.search("add to cart", text, re.IGNORECASE):
                if url in neSkipList:
                    print("[REPEAT STOCK] Link:", url, neSkipList[url], "Rotations left.")
                    neSkipList[url] -= 1
                    if neSkipList[url] <= 0:
                        neSkipList.pop(url)
                    time.sleep(random.randint(1,3))
                    continue
                await channel.send("There might be a {} at {}".format(neGpuList[x], neUrlList[x]))
                print("[POSSIBLE STOCK] Link:", neUrlList[x])
                neSkipList[url] = 2
                time.sleep(random.randint(1,3))
            else:
                print("[OUT OF STOCK] Link:", neUrlList[x])
                time.sleep(random.randint(1,3))
                
@client.event            
async def on_ready():
    channel = client.get_channel(################)
    threading.Thread(target=asyncio.run, args = (bB(channel),)).start()
    threading.Thread(target=asyncio.run, args = (ne(channel),)).start()

##Also tried the following
##asyncio.run_coroutine_threadsafe(ne(channel), #Something Here#)
##asyncio.run_coroutine_threadsafe(bB(channel), #Something Here#)



client.run(token)

【问题讨论】:

    标签: python multithreading asynchronous discord coroutine


    【解决方案1】:

    我认为这没有按预期工作有两个主要原因,第一个是 requests 模块是为同步 IO 构建的,不能与异步正常工作。 [See here for more] 你可以尝试用类似aiohttp 的东西替换你的requests 模块。

    其次,time.sleep() 是阻塞的,asyncio.sleep() 是非阻塞的。在异步循环的上下文中,asyncio 将告诉特定线程等待,而您的整个代码将被允许继续。

    在您的代码中,这将放在一起看起来像:

    import time
    import re
    import discord
    import threading
    import random
    import asyncio
    import aiohttp
    from discord.ext import tasks
    
    
    bbUrlList = []
    neUrlList = []
    neGpuList = []
    neSkipList = {}
    
    client = discord.Client()
    
    with open("DiscordToken.txt",'r') as tokenFile:
        token = str(tokenFile.readline()).replace("Token=","")
    
    with open("bb.txt",'r') as file:
            for line in file:
                bbUrlList.append(line.split(" ")[1])
    
    with open("ne.txt",'r') as file:
            for line in file:
                neUrlList.append(line.split(" ")[1])
                neGpuList.append(line.split(" ")[0])
    
    async def bB(channel):
        async with aiohttp.ClientSession() as session:
            while True:
                for x in range(0,len(bbUrlList)):
                    url = bbUrlList[x]
                    headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.85 Safari/537.36'}
                    async with session.get(url, headers=headers) as request:
                        text = await request.text()
                        if re.search("add to cart", text, re.IGNORECASE) or re.search("see details", text, re.IGNORECASE):
                            await channel.send("Bb appears to be dropping NOW!")
                            print("[POSSIBLE DROP] Link:", bbUrlList[x])
                            await asyncio.sleep(1800)
                        else:
                            print("[OUT OF STOCK] Link:", bbUrlList[x])
                            await asyncio.sleep(random.randint(1,3))
    
    async def ne(channel):
        async with aiohttp.ClientSession() as session:
            while True:
                for x in range(0,len(neUrlList)):
                    url = neUrlList[x]
                    gpu = neGpuList[x]
                    headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.85 Safari/537.36'}
                    async with session.get(url, headers=headers) as request:
                        text = await request.text()
                        if re.search("add to cart", text, re.IGNORECASE):
                            if url in neSkipList:
                                print("[REPEAT STOCK] Link:", url, neSkipList[url], "Rotations left.")
                                neSkipList[url] -= 1
                                if neSkipList[url] <= 0:
                                    neSkipList.pop(url)
                                await asyncio.sleep(random.randint(1,3))
                                continue
                            await channel.send("There might be a {} at {}".format(neGpuList[x], neUrlList[x]))
                            print("[POSSIBLE STOCK] Link:", neUrlList[x])
                            neSkipList[url] = 2
                            await asyncio.sleep(random.randint(1,3))
                        else:
                            print("[OUT OF STOCK] Link:", neUrlList[x])
                            await asyncio.sleep(random.randint(1,3))
                    
    @client.event            
    async def on_ready():
        channel = client.get_channel(################)
        threading.Thread(target=asyncio.run, args = (bB(channel),)).start()
        threading.Thread(target=asyncio.run, args = (ne(channel),)).start()
    
    
    client.run(token)
    

    我没有大量使用 aiohttp 的经验,因此请务必查看 its documentation 以根据您的特定需求进行定制。

    祝你的项目好运!

    【讨论】:

    • 谢谢,我给它拍个照,然后报告。
    • 遗憾的是,这仍然给了我同样的超时错误。不过感谢您的意见。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-12-25
    • 2019-07-16
    • 2020-07-23
    • 2020-09-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多