Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/xcode/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 3.x 使用子流程避免长时间运行的任务断开discord.py bot的连接?_Python 3.x_Subprocess_Python Asyncio_Discord.py - Fatal编程技术网

Python 3.x 使用子流程避免长时间运行的任务断开discord.py bot的连接?

Python 3.x 使用子流程避免长时间运行的任务断开discord.py bot的连接?,python-3.x,subprocess,python-asyncio,discord.py,Python 3.x,Subprocess,Python Asyncio,Discord.py,我为我的Discord服务器创建了一个bot,该bot会转到给定子Reddit的Reddit API,并根据您输入的子Reddit在Discord聊天中发布当天的前10个结果。它忽略了自我发布,实际上只发布图片和礼物。Discord message命令如下所示:=get搞笑的awww新闻编程,在每个子Reddit从Reddit API(PRAW)获取结果时发布结果。这样做没有问题。我知道bot能够点击API并发布到discord 我添加了另一个命令=getshuffled,该命令将子reddit

我为我的Discord服务器创建了一个bot,该bot会转到给定子Reddit的Reddit API,并根据您输入的子Reddit在Discord聊天中发布当天的前10个结果。它忽略了自我发布,实际上只发布图片和礼物。Discord message命令如下所示:
=get搞笑的awww新闻编程
,在每个子Reddit从Reddit API(PRAW)获取结果时发布结果。这样做没有问题。我知道bot能够点击API并发布到discord

我添加了另一个命令
=getshuffled
,该命令将子reddit的所有结果放入一个大列表中,然后在发布之前将其洗牌。这在多达50个子站点的请求中非常有效

这就是我需要帮助的地方:

因为它可能是一个如此大的结果列表,100多个子网站上有1000多个结果,所以这个机器人会在非常大的请求上崩溃。根据我从问题中得到的帮助,我了解出了什么问题。bot正在启动,它正在与我的Discord服务器通信,当我向它传递一个长请求时,它会在redditapi调用完成时停止与服务器通信太长时间,如果Discord连接失败

因此,我认为我需要做的是,为代码提供一个子流程,该子流程将进入Reddit API并提取结果(我认为这将使discord连接保持运行),然后在完成后将这些结果传递回bot

或者。。。这是Asyncio可以自己处理的事情

正如我所知道的那样,我很难处理子流程调用

基本上,我要么需要这个子流程技巧的帮助,要么需要知道我是否是个白痴,Asyncio可以帮我处理所有这些。我认为这只是那些“我不知道我不知道什么”的例子之一

因此,简单地说:机器人运行良好,洗牌的子Reddit数量较少。它通过发送的args(是subreddits),获取每个帖子的信息,然后在发布到discord的链接之前洗牌。问题是当它是一个较大的子reddit集合~50+时。为了让它能够处理更大的数量,我需要让Reddit调用不阻塞主discord连接,这就是为什么我要尝试创建一个子流程

Python版本为3.6,Discord.py版本为0.16.12 此bot托管并运行在Pythonywhere上

代码:

。这是我的get_reddit.py文件:

#THIS CODE WORKS, JUST NEED TO CALL THE FUNCTION AND RETURN RESULTS
#TO THE MAIN_LOOP FUNCTION

from redditBot_auth import reddit
import random

def is_number(s):
    try:
        int(s)
        return True
    except:
        pass

def show_title(s):
    try:
        if s == 'TITLES':
            return True
    except:
        pass

async def get_results(*args, shuffled=False):

    q=10

    #This takes a integer value argument from the input string.
    #It sets the number variable,
    #Then deletes the number from the arguments list.
    title = False
    for item in args:
        if is_number(item):
            q = item
            q = int(q)
            if q > 15:
                q=15
            args = [x for x in args if not is_number(x)]

        if show_title(item):
            title = True
            args = [x for x in args if not show_title(x)]

    results=[]

    TESTING = False #If this is turned to True, the subreddit of each post will be posted. Will use defined list of results.
    NoGrabResults = False

    #This pulls the data and creates a list of links for the bot to post

    if NoGrabResults == False:
        for item in args:
            try:
                #get the posts
                #put them in results list    

            except Exception as e:
                #handle error
                pass

        try:
            #print('____SHUFFLED___')
            random.shuffle(results)
            random.shuffle(results)
            random.shuffle(results)

        except:
            #error stuff

        print(results)
#I should be able to read that print statement for the results, 
#and then use that in the main bot function to post the results.

更新:根据建议,我让命令通过ThreadPoolExecutor传递,如图所示:

async def main(*args, shuffled):

    if shuffled==True:

        with concurrent.futures.ThreadPoolExecutor() as pool:
            results = await asyncio.AbstractEventLoop().run_in_executor(
                executor=pool, func=await main_loop(*args, shuffled=True))
            print('custom thread pool', results)
但是,当脚本试图与Discord对话时,这仍然会导致错误:

ERROR:asyncio:Task was destroyed but it is pending!
task: <Task pending coro=<Client._run_event() running at /home/GageBrk/.local/lib/python3.6/site-packages/discord/client.py:307> wait_for=<Future pending cb=[<TaskWakeupMethWrapper object at 0x7f28acd8db28>()]>>
Event loop is closed
Destination must be Channel, PrivateChannel, User, or Object. Received NoneType
Destination must be Channel, PrivateChannel, User, or Object. Received NoneType
Destination must be Channel, PrivateChannel, User, or Object. Received NoneType
...
错误:asyncio:任务已销毁,但正在挂起!
任务:
事件循环已关闭
目标必须是频道、PrivateChannel、用户或对象。接收非类型
目标必须是频道、PrivateChannel、用户或对象。接收非类型
目标必须是频道、PrivateChannel、用户或对象。接收非类型
...

它正在正确发送结果,但discord仍在丢失连接。

praw
依赖于
请求库,这是同步的,意味着代码被阻塞。如果阻塞代码执行时间过长,这可能会导致bot冻结

为了解决这个问题,可以创建一个单独的线程来处理阻塞代码。下面是一个例子。注意
blocking_功能
将如何使用
时间。sleep
将阻塞10分钟(600秒)。这应该足以冻结并最终使机器人崩溃。但是,由于该函数在自己的线程中使用
run\u in\u executor
,因此bot将继续正常运行

import time
import asyncio
from discord.ext import commands
from concurrent.futures import ThreadPoolExecutor

def blocking_function():
    print('entering blocking function')
    time.sleep(600)
    print('sleep has been completed')
    return 'Pong'

client = commands.Bot(command_prefix='!')

@client.event
async def on_ready():
    print('client ready')

@client.command()
async def ping():
    loop = asyncio.get_event_loop()
    block_return = await loop.run_in_executor(ThreadPoolExecutor(), blocking_function)
    await client.say(block_return)

client.run('token')

praw
依赖于
请求
库,这是同步的,意味着代码被阻塞。如果阻塞代码执行时间过长,这可能会导致bot冻结

为了解决这个问题,可以创建一个单独的线程来处理阻塞代码。下面是一个例子。注意
blocking_功能
将如何使用
时间。sleep
将阻塞10分钟(600秒)。这应该足以冻结并最终使机器人崩溃。但是,由于该函数在自己的线程中使用
run\u in\u executor
,因此bot将继续正常运行

import time
import asyncio
from discord.ext import commands
from concurrent.futures import ThreadPoolExecutor

def blocking_function():
    print('entering blocking function')
    time.sleep(600)
    print('sleep has been completed')
    return 'Pong'

client = commands.Bot(command_prefix='!')

@client.event
async def on_ready():
    print('client ready')

@client.command()
async def ping():
    loop = asyncio.get_event_loop()
    block_return = await loop.run_in_executor(ThreadPoolExecutor(), blocking_function)
    await client.say(block_return)

client.run('token')

您使用什么代码或库从RedditAPI获取结果?如果您使用的是
请求
,则这可能会阻止并使您的bot崩溃。尝试切换到
aiohttp
。看这里:我正在使用praw模块。机器人能够从reddit获得结果没有问题,问题是当我试图将结果传递给机器人时,它崩溃了。这就是我试图启动子进程的原因,这样子进程就不会超时。
praw
使用阻塞的
requests
库,这意味着长时间的查询将导致您的bot崩溃(正如您所注意到的)。如果在bot调用的函数中使用类似于
time.sleep(600)
的东西,然后再打印
打印应该发生,但bot将崩溃。您可以使用
ThreadPoolExecutor
使函数异步。请看这里:好吧,请你看看……我有一种烦人的感觉,这是可以用Asyncio完成的!“我现在就去试一试。”本津编辑:好的。我将此作为指导:我走在正确的轨道上。您使用什么代码或库从RedditAPI获取结果?如果您使用的是
请求
,则这可能会阻止并使您的bot崩溃。尝试切换到
aiohttp
。看这里:我正在使用praw模块。机器人能够从reddit获得结果没有问题,问题是当我试图将结果传递给机器人时,它崩溃了。这就是为什么我要这么做
import time
import asyncio
from discord.ext import commands
from concurrent.futures import ThreadPoolExecutor

def blocking_function():
    print('entering blocking function')
    time.sleep(600)
    print('sleep has been completed')
    return 'Pong'

client = commands.Bot(command_prefix='!')

@client.event
async def on_ready():
    print('client ready')

@client.command()
async def ping():
    loop = asyncio.get_event_loop()
    block_return = await loop.run_in_executor(ThreadPoolExecutor(), blocking_function)
    await client.say(block_return)

client.run('token')