python - 使用 irc.bot.SingleServerIRCBot 保留线程(与 twitch 一起使用)

标签 python multithreading irc twitch

向包含 SingleServerIRCBot 的线程发送断开连接信号的正确方法是什么?

我正在实例化连接到 twitch 的机器人

import threading
import irc.bot
class MyBot(irc.bot.SingleServerIRCBot):
    ...
bot = MyBot(...)
threads = []
t = threading.Thread(target=bot.start()
threads.append(t)
t.start()

当流不再存在时,无论我尝试什么,我都无法让线程成功结束。我应该如何向线程发送信号,告诉它退出 channel ,杀死机器人,然后杀死它自己?

可以在此处找到 .start 方法的代码 https://github.com/jaraco/irc/blob/master/irc/bot.py#L331

我的第一个想法是使用具有退出条件的 while 循环覆盖该方法。不过到目前为止我还没有遇到任何运气。

此外,这里还有一个.die方法https://github.com/jaraco/irc/blob/master/irc/bot.py#L269但是当线程执行无限循环时如何调用该方法?

尝试直接终止线程最终会导致它们持续存在,并最终引发有关我的进程正在运行的线程总数的错误。

编辑赏金:我也会接受一个答案,该答案描述了一次处理多个 IRC 机器人的更好方法。

最佳答案

我认为您不能(或应该)直接终止线程,但您可以停止在该线程上运行的任务。然后该线程将处于非事件状态,如果您愿意,您可以将其从线程列表中删除。我不熟悉 SingleServerIRCBot,但我将使用下面的类作为示例。

import time

class MyTask:
    def __init__(self):
        self._active = True

    def start(self):
        while self._active:
            print('running')
            time.sleep(1)

    def die(self):
        self._active = False
<小时/>

在Python3中,线程有一个_target属性,我们可以通过它访问目标函数/方法。我们可以使用此属性来访问目标的对象并调用die方法(例如:thread._target.__self__.die())。不过,我认为最好是子类 Thread 并将目标对象存储在变量中,因为 _target 是私有(private)属性,也是出于兼容性原因。

import threading

class MyThread(threading.Thread):
    def __init__(self, target, args=()):
        super(MyThread, self).__init__()
        self.target = target
        self.args = args

    def run(self):
        self.target.start(*self.args)

    def stop_task(self):
        self.target.die()

使用此类,我们将传递一个 MyTask 对象作为目标,并且将从 MyThread.run 调用 start 方法。现在我们可以使用 MyThread.stop_task 来停止该线程上运行的任务。

o = MyTask()
t = MyThread(target=o)
t.start()
t.stop_task()
time.sleep(1.1)
print(t.is_alive())

请注意,我等待 1.1 秒来测试线程是否处于事件状态。这是因为目标 (MyTask.start) 最多需要一秒钟才能停止。此方法不会终止线程,而是调用 MyTask.die 并等待任务完成。如果您想立即结束任务(并释放任务使用的任何资源),您可以使用 Process 并以 .terminate 结束它。 。如果您的任务执行的 CPU 操作多于 IO 操作,您还应该选择多处理而不是多线程,因为进程不受 GIL 的限制。 。

<小时/>

在研究源代码之后,我注意到.die()调用了sys.exit,所以我们不能用它来终止任务,因为它会停止该程序。看来原因是.start()调用父对象的.start() ,然后调用 .process_forever() Reactor 对象的方法。该方法开始运行Reactor.process_once()在没有中断条件的无限循环中。

一个可能的解决方案是子类化 SingleServerIRCBot 并使用 bool 变量来打破循环。此类应覆盖 .start().die(),以便停止在线程上运行的机器人。 .die() 方法会将标志设置为 false,而 .start() 将在循环中调用 Reactor.process_once()

import irc.bot

class MyBot(irc.bot.SingleServerIRCBot):
    def __init__(self, channel, nickname, server, port=6667):
        super(MyBot, self).__init__([(server, port)], nickname, nickname)
        self.channel = channel
        self._active = True

    def start(self):
        self._connect()
        while self._active:
            self.reactor.process_once(timeout=0.2)

    def die(self, msg="Bye, cruel world!"):
        self.connection.disconnect(msg)
        self._active = False

现在我们可以通过在运行机器人的线程上调用 .stop_task() 来停止机器人,或者直接调用机器人的 .die() 方法.

host, port = 'irc.freenode.net', 6667
nick = 'My-Bot'
channel = '#python'

bot = MyBot(channel, nick, host, port)
t = MyThread(bot)
t.start()
t.stop_task()
#bot.die()

关于python - 使用 irc.bot.SingleServerIRCBot 保留线程(与 twitch 一起使用),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53076695/

相关文章:

python - 使用列表理解填充 pandas 值字典

python - Matplotlib自动化学式下标使用不带斜体文本

python - pyglet 显示的 numpy 数组不正确

java - 多线程使用中的变量声明,Java [内存泄漏问题]

c++ - 多线程 galib247 遗传算法卡在局部最大值

php - 我的PHP脚本无法连接到IRC服务器

Python IRC 机器人,不会停止循环

python - 找到从点到复杂曲线的最小距离

JAVA消费者-生产者多线程应用程序——代码流程

python - 根据前缀限制列表中字符串的出现