Python类中的简单线程管理

2 投票
3 回答
5033 浏览
提问于 2025-04-17 08:05

我正在尝试为Python写一个模块,这个模块可以在我的程序中打印文本,并在后台执行某些操作时显示进度条。目前我在使用“threading”模块,但如果有其他更简单的方法,我也愿意尝试。

我想知道的有两个方面,我应该如何优雅地调用这个类,以及我应该如何停止我创建的线程?

这是我目前的做法:

tmp1 = textprint("hello this is text")
tmp1.start()
# do something
tmp1.stop()

这些是我考虑过的选项,并且已经查看过:

  • 使用 thread.name 来找到线程的名字,或者让线程返回一个名字以便之后停止它。或者传递一个数字来进行类似的线程识别。(这有点麻烦,并不是我最喜欢的解决方案。)

    发送一个线程事件?- 从文档中我看到可以发送事件,也许可以用它来停止线程?

    或者使用with语句,但我不太清楚在这个上下文中如何使用,而且我觉得大部分Python文档都非常混乱,根本不是为我写的。

我想要做的事情是这样的:

echo('hello')(打印进度条等)- 然后当我想停止它时,使用echo.stop()

不过明显的问题是,stop函数不知道它要停止哪个线程。

这是我尝试做的一个框架:

import time
import string
import threading

class print_text(threading.Thread):

    def __init__(self,arg=None):
        super(print_text,self).__init__()
        self._stop = False
        self.arg=arg

    def run (self):
        # start thread for text
        print self.txt
        while not self._stop:
                print "rude words"

    def echo (self,txt):
        self.txt=txt
        self.start()

    def stop(self):
        self._stop = True

    def stopped(self):
        return self._stop == True

    def __enter__(self):
        print "woo"
        return thing

    def __exit__(self, type, value, traceback):
        return isinstance(value, TypeError)


if __name__ == '__main__':

    print_text.start.echo('this is text') # dunt werk

    with print_text.echo('this is text'):
           time.sleep(3)

    print "done"

然后像这样调用它:

echo('this is text') 

我还猜为了做到这一点,我需要

import echo from print_text 

使用WITH的方式建议在里面放一个__enter____exit__的部分。我试过这些,但它们没有奏效,而且我也不知道自己在做什么,真的很感谢任何帮助,谢谢。

3 个回答

0

线程的名字很有用,特别是当你可能同时有多个子线程在运行同样的任务时,这样你就可以确保所有的子线程都能被停止。给线程起名字听起来是个不错的主意,而且也不会太麻烦,不过每个人的看法可能不同 :-)。下面是一些内容:

  • 启动一个子线程来打印消息并显示一个进度条。
  • 使用启动时给定的名字来停止这个子线程。

这样代码就简单多了。这样做能达到你的目的吗?

import time, threading

class print_text:

    def __init__(self):
        pass

    def progress(self):
        while not self._stop:       # Update progress bar
            print(".", sep="", end="")
            time.sleep(.5)

    def echo(self, arg="Default"):  # Print message and start progress bar
        print(arg)
        self._stop = False
        threading.Thread(target=self.progress, name="_prog_").start()

    def stop(self):
        self._stop = True
        for t in threading.enumerate():
            if t.name == "_prog_":
                t.join()

tmp1 = print_text()
tmp1.echo("hello this is text")
time.sleep(10)
tmp1.stop()
print("Done")
3

在Python中,停止一个线程的最好方法是礼貌地请求它停止。传递新数据给线程的最佳方式是使用Queue模块。

这两者在这篇文章中的代码中都有用到,代码展示了如何通过Python线程进行套接字通信,但与您的问题同样相关。如果你仔细阅读代码,你会注意到:

  1. 使用了threading.Event(),这个事件是通过外部的方法调用来设置的,线程会定期检查这个事件,以知道是否被请求停止。
  2. 使用Queue.Queue()来传递命令给线程,并接收它的响应。
4

你离写出能运行的代码已经很近了。只需要做一些小调整:

  • print_text 是一个类。你需要用 print_text() 来创建它的实例。
  • start 方法会返回一个 print_text 的实例,你需要把这个实例保存下来,这样才能调用 stopechot = print_text()
  • enter 方法需要返回 self,而不是 thing
  • exit 方法应该设置 _stop 或者调用 stop()
  • echo 方法应该返回 self,这样才能和 with 语句一起使用。

下面是包含这些小修改的可运行代码:

import time
import string
import threading

class print_text(threading.Thread):

    def __init__(self, arg=None):
        super(print_text,self).__init__()
        self._stop = False
        self.arg=arg

    def run (self):
        # start thread for text
        print self.txt
        while not self._stop:
                print "rude words"

    def echo (self, txt):
        self.txt=txt
        self.start()
        return self

    def stop(self):
        self._stop = True

    def stopped(self):
        return self._stop == True

    def __enter__(self):
        print "woo"
        return self

    def __exit__(self, type, value, traceback):
        self._stop = True
        return isinstance(value, TypeError)


if __name__ == '__main__':

    t = print_text()
    t.echo('this is text')
    time.sleep(3)
    t.stop()

    with print_text().echo('this is text'):
        time.sleep(3)

    print "done"

撰写回答