使用子进程来避免长时间运行的任务断开discord.py bot?

2024-01-22

我为我的 Discord 服务器创建了一个机器人,它会转到给定 subreddit 的 Reddit API,并根据您输入的 subreddit 在 Discord 聊天中发布当天的前 10 个结果。它忽略自己的帖子,实际上只发布图片和 GIF。 Discord 消息命令看起来像这样:=get funny awww news programming,发布每个 Reddit 子版块从 Reddit API (PRAW) 获取的结果。这没有问题。我知道机器人能够访问 API 并发布不和谐内容。

我添加了另一个命令=getshuffled它将 Reddit 子版块的所有结果放入一个大列表中,然后在发布之前对它们进行打乱。这对于最多 50 个 subreddits 的请求非常有效。

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

因为它可能是一个如此大的结果列表,来自 100 多个 subreddits 的 1000 多个结果,所以机器人在处理真正大的请求时会崩溃。根据我从问题中得到的帮助昨天 https://stackoverflow.com/questions/53575836/python-discord-py-program-building-large-list-is-running-out-of-memory-and-crash,我明白出了什么问题。机器人正在启动,它正在与我的 Discord 服务器通信,当我向它传递一个长请求时,它在 Reddit API 调用完成时停止与服务器通信太长时间,并且 Discord 连接失败。

那么,我think我需要做的是,为代码建立一个子进程,用于访问 Reddit API 并提取结果(我认为这将使不和谐连接保持运行),然后在完成时将这些结果传递回机器人。 ...

或者...这是 Asyncio 可以自行处理的事情...

正如我所知道的那样,我在子流程调用方面遇到了困难。

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

回顾一下:该机器人在少量的 subreddits 被洗牌的情况下工作得很好。它会遍历发送的参数(它们是 Reddit 子版块),获取每个帖子的信息,然后在将链接发布到不和谐之前进行洗牌。问题是当它是一个更大的 Reddit 子集(大约 50+)时。为了让它能够处理更大的数量,我需要让 Reddit 调用不阻止主要的不和谐连接,这就是我尝试创建一个子进程的原因。

Python版本是3.6,Discord.py版本是0.16.12 该机器人在 PythonAnywhere 上托管并运行

Code:

from redditBot_auth import reddit

import discord
import asyncio
from discord.ext.commands import Bot
#from discord.ext import commands
import platform
import subprocess
import ast

client = Bot(description="Pulls posts from Reddit", command_prefix="=", pm_help = False)

@client.event
async def on_ready():
    return await client.change_presence(game=discord.Game(name='Getting The Dank Memes')) 

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 main_loop(*args, shuffled=False):
    print(type(args))

    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)]

    number_of_posts = q * len(args)
    results=[]

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


    if shuffled == False: #If they don't want it shuffled

        for item in args:
            #get subreddit results
            #post links into Discord as it gets them
            #The code for this works

    else: #if they do want it shuffled
        output = subprocess.run(["python3.6", "get_reddit.py", "*args"])
        results = ast.literal_eval(output.decode("ascii"))
        # ^^ this is me trying to get the results back from the other process.

。这是我的 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.

.

@client.command()
async def get(*args, brief="say '=get' followed by a list of subreddits", description="To get the 10 Top posts from a subreddit, say '=get' followed by a list of subreddits:\n'=get funny news pubg'\n would get the top 10 posts for today for each subreddit and post to the chat."):
    #sr = '+'.join(args)
    await main_loop(*args)

#THIS POSTS THE POSTS RANDOMLY   
@client.command()
async def getshuffled(*args, brief="say '=getshuffled' followed by a list of subreddits", description="Does the same thing as =get, but grabs ALL of the posts and shuffles them, before posting."):

    await main_loop(*args, shuffled=True)


client.run('my ID')

UPDATE:根据建议,我将命令通过 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
...

它正在正确发送结果,但不和谐仍然失去连接。


praw依赖于requests库,这是同步的,意味着代码是阻塞的。如果阻止代码执行时间过长,这可能会导致您的机器人冻结。

为了解决这个问题,可以创建一个单独的线程来处理阻塞代码。下面是一个例子。注意如何blocking_function将使用time.sleep阻止 10 分钟(600 秒)。这应该足以冻结并最终导致机器人崩溃。但是,由于该函数在它自己的线程中使用run_in_executor,机器人继续正常运行。

新版本

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(ctx):
    loop = asyncio.get_event_loop()
    block_return = await loop.run_in_executor(ThreadPoolExecutor(), blocking_function)
    await ctx.send(block_return)

client.run('token')

Older async version

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')
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用子进程来避免长时间运行的任务断开discord.py bot? 的相关文章

  • 如何在 pygame 中制作一个进入网站的按钮?

    我的 pygame 中有一个 Credits 菜单 我想制作一些可以访问某些网站的按钮 我的意思是 当单击按钮时 它应该打开 例如 GitHub 或任何链接 有什么方法可以实现这个目标吗 实施一个Button类并使用网页浏览器 https
  • Thread 内调用协程

    是否可以使线程运行方法异步 以便它可以在其中执行协程 我意识到我正在混合范例 我正在尝试集成使用协程的第三方库 而我的项目使用线程 在考虑更新我的项目以使用协程之前 我想探索在线程中执行协程 下面是我的示例用例 其中我有一个线程 但我想从线
  • 为什么打印出来是这样的

    下面的代码片段中的迭代是如何进行的 a 0 1 2 3 b for a 1 in a b append a 1 print b Output is 0 1 2 2 Python for循环使用赋值 如果使用不当 可能会导致有趣的结果 您的示
  • 尝试在 PyQt5 中的 pyqtgraph 绘图小部件中获取带有坐标显示的光标

    我正在尝试在 PyQt5 的 pqytplot 图小部件中添加光标位置的读数 我发现这段代码可以实现我想要的功能 但是在一个独立的窗口中 所有这些都在一个程序文件中 import pyqtgraph as pg from pyqtgraph
  • Replit Discord 机器人已被 Discord 屏蔽

    当我在 repl it 上运行不和谐机器人时 出现错误 在错误中 我看到下面一些 HTML 代码 CloudFlare 似乎阻止了我的机器人访问 Discord 是什么导致了这种情况 section class w 240 lg w ful
  • Python Tkinter Tk 支持清单框吗?

    我正在尝试在 GUI 中创建清单框 可以做 Tkinter 吗 我不想要复选框列表 我知道 Python Wx GUI 开发有这种支持 但我正在寻找 Tk 中的支持 如果有人有想法 请分享详细信息或方法的链接 Tkinter 没有像 wxP
  • 熊猫不工作:DataFrameGroupBy;面板分组依据

    我刚刚升级了 python 但无法让 pandas 正常运行 请参见下文 似乎没有任何效果 回溯 最近一次调用最后一次 文件 Library Frameworks Python framework Versions 3 8 lib pyth
  • 为什么我在迭代 28 后收到错误:“JSONDecodeError:期望值:第 1 行第 1 列(字符 0)”? [复制]

    这个问题在这里已经有答案了 我正在尝试从政府的 API 中提取数据 该 API 分为多个页面 每页有 10 个观察结果 我编写了一个算法 可以从每个观察中获取重要信息并将其添加到 pandas 数据框中 一切都很顺利 直到我到达迭代 29
  • 如何使用 python 的 asyncio 模块正确创建和运行并发任务?

    我正在尝试正确理解并实现两个同时运行的Task https docs python org 3 library asyncio task html task使用Python 3相对较新的对象asyncio https docs python
  • Python DataFrame:将一列转置为多列

    我有一个如下所示的数据框 df pd DataFrame month 2017 09 27 2017 09 27 2017 09 28 2017 09 29 Cost 100 500 200 300 我怎样才能得到这样的 df 2017 0
  • 调用 close() 后大文件没有立即刷新到磁盘?

    我正在使用 python 脚本创建大文件 超过1GB 实际上有 8 个 在创建它们之后 我必须创建将使用这些文件的进程 该脚本如下所示 This is more complex function but it basically does
  • \ufeff 标识符中的无效字符

    我有以下代码 import urllib request try url https www google com search q test headers usag Mozilla 5 0 Macintosh Intel Mac OS
  • 无法保存自定义子类模型

    灵感来自tf keras Model 子类化 https www tensorflow org guide keras model subclassing我创建了自定义模型 我可以训练它并获得成功的结果 但是我无法保存它 我使用 pytho
  • 强制 shell 在 SunGrid 引擎中使用 conda 变量中的 python [重复]

    这个问题在这里已经有答案了 我正在尝试在 SunGrid 引擎中执行 python 文件 并且从 anaconda3 环境变量中执行它 我的代码很简单 from future import print function import url
  • matplotlib x 轴时间重叠

    我用以下函数及时绘制比特率 usr bin python3 import matplotlib pyplot as plt import datetime def plotBitrate time bitrate filename time
  • 如何在不重复代码的情况下定义 randint 元组?

    我经常使用 randint 元组来表示颜色值等 a b c randint 0 255 randint 0 255 randint 0 255 当我认为必须有更好的方法时 有吗 使用numpy 1 import numpy as np tu
  • Jupyter 笔记本无法连接到内核

    我正在尝试使用 Python 3 内核 检查它是否在 kernelspec 列表中 我创建了一个笔记本 并在第一个单元格中print test 当我执行单元格时 什么也没有发生 我刚看到In 它似乎永远不会执行 最终我得到 Connecti
  • Flask 从线程中删除会话变量

    我尝试实施投票系统 它的工作原理是这样的 如果用户对帖子进行投票 我会在会话变量中记录其临时状态 已投票 已加星标等 如果当前用户在我将结果保存到临时表之前尚未投票 用户可以在 5 分钟内更改投票 5 分钟后 结果将使用线程永久写入数据库
  • 适用于 Python 的旧版本 Windows 二进制库 Wheel 的存储库?

    作为很多用户 我使用很棒的Christopher 的 Windows 二进制轮子 http www lfd uci edu gohlke pythonlibs vlfd当尝试在 Windows 上安装一些 python 包 例如 GDAL
  • 类型错误:需要 Future 或协程

    我尝试在 asyncssh 上自动重新连接 ssh 客户端 SshConnectManager 必须留在后台并在需要时进行 ssh 会话 class SshConnectManager object def init self host u

随机推荐

  • javascript中的尾部函数[重复]

    这个问题在这里已经有答案了 我想创建一个添加参数的函数 调用这个函数应该是 functionAdd 2 3 4 n 结果 2 3 4 n 我正在尝试这个 function myfunction num var summ num if num
  • 如何将代码从旧版本的xcode转移到最新版本?

    我有一个xcode我不久前制作的一个应用程序的项目 但它已经启动xcode 3 2 如何轻松地将项目转移到较新版本的xcode 我尝试手动将项目的每个文件传输到新版本 但不是很成功 有没有更简单 更自动化的方法来做到这一点 编辑 从 xco
  • 为什么函数 apply 会抱怨长列表?

    作为一些欧拉阵痛 http projecteuler net 我正在尝试编写一个埃拉托斯特尼筛法 https en wikipedia org wiki Sieve of Eratosthenes带有因式分解轮 到目前为止我的代码是 def
  • 如何从 Java servlet Web 容器正确实现 RabbitMQ RPC?

    我希望传入的 Java servlet Web 请求使用 RPC 方法调用 RabbitMQ 如上所述here http www rabbitmq com tutorials tutorial six java html 但是 我不确定如何
  • 使用 javascript/html 控制 iframe 内容

    在我的网页中 我有一个像这样的 iframe iframe 是同一网站上的页面 我的问题是 是否可以在具有 iframe 的页面上使用 javascript 来控制 thispage html 例如使用 javascript 函数 是的你可
  • 在 Meteor 移动应用程序 (cordova) 上登录 Facebook?

    我正在寻找使用 Meteor Cordova 构建移动应用程序 首先希望 Facebook 登录能够正常工作 显然默认的 account facebook 包不起作用 所以我环顾了一下气氛 只找到了 article4dev cordova
  • AWS代码构建列出其他帐户的s3存储桶

    I have my codebuild build sitting on Account A and s3 buckets on Account B I tried to set up a trusted IAM STS role on A
  • 如何将命令绑定到本地事件?

    我有一个应该捕获 KeyDown KeyUp 事件的表单 此代码在 NRE 中失败 因为它在我当前的视图上查找 KeyDown 控件 this BindCommand ViewModel vm gt vm KeyDown KeyDown 我
  • 在Python中计算给定纬度和经度数据的距离矩阵的有效方法

    我有纬度和经度的数据 我需要计算两个包含位置的数组之间的距离矩阵 我用过这个This https stackoverflow com questions 120283 working with latitude longitude valu
  • JavaScript 中的 onclick 事件函数

    我在带有按钮的 HTML 页面中有一些 JavaScript 代码 我有一个函数叫做click 处理onClick按钮的事件 按钮的代码如下
  • Shell 函数字符串变量在 While 循环和 case 后结果为空?

    为什么我没有得到echo User password is typo 结果 我如何在 while 循环之后得到最后的拼写错误结果 bin sh pass mes read sp Password passvar echo passvar p
  • 以特定方式对 Select 子句结果进行排序

    我需要帮助编写select子句查询 例如 假设我有一个这样的查询 select value from some table order by value asc 结果我得到这个 1 2 3 4 5 6 7 8 9 10 但我想写的一个特殊查
  • Django 安装错误(没有名为 Django 的模块)

    我使用的是 Mac OS X Mavericks 我安装 Django 时出错 我使用 pip install 命令安装了 Django 它位于下面的目录中 Requirement already satisfied use upgrade
  • 最佳布局算法[重复]

    这个问题在这里已经有答案了 我正在根据本文在 ASP NET 应用程序中实现 CSS Sprites 设置 http weblogs asp net zowens archive 2008 03 05 css sprite for asp
  • 禁用Oracle中的所有表约束

    如何使用单个命令禁用 Oracle 中的所有表约束 这可以针对单个表 表列表或所有表 最好避免写出临时假脱机文件 使用 PL SQL 块 您可以从 SQL Plus 运行它或将其放入包或过程中 与 USER TABLES 的连接是为了避免视
  • nuget 更新后样式变得混乱。

    我更新了默认 MVC 应用程序的多个 nuget 包 但我的页面样式弄乱了 看起来正在加载部分样式 但我无法找出问题所在 提前致谢 更新前我的导航栏 更新后我的导航栏 很遗憾听到这个消息 我也遇到了同样的问题 也花了我很多钱 太令人沮丧了
  • 帮我推理 F# 线程

    在闲逛一些 F 通过 MonoDevelop 时 我编写了一个例程 它用一个线程列出目录中的文件 let rec loop path string Array append path gt Directory GetFiles path g
  • getCacheFiles() 和 getLocalCacheFiles() 是否相同?

    As 获取本地缓存文件 http hadoop apache org docs r2 3 0 api org apache hadoop mapreduce JobContext html getLocalCacheFiles 已被弃用 我
  • 引导开关事件处理程序不工作

    我问了一个与此类似的问题here https stackoverflow com questions 22460608 bootstrap switch js being called but doing nothing但现在我坚持使用 B
  • 使用子进程来避免长时间运行的任务断开discord.py bot?

    我为我的 Discord 服务器创建了一个机器人 它会转到给定 subreddit 的 Reddit API 并根据您输入的 subreddit 在 Discord 聊天中发布当天的前 10 个结果 它忽略自己的帖子 实际上只发布图片和 G