【问题标题】:Python, Stop a ThreadPython,停止线程
【发布时间】:2017-12-07 22:13:39
【问题描述】:

我正在尝试创建一个 ping IP 地址并记录连接/未连接时间的类。

由于这个类是 GUI 的一部分,我希望在用户询问时停止这个线程。

发现一些 Q&A 重新评估了这个问题,但没有一个真正导致线程停止。

我正在尝试创建一个方法,该类的一部分将停止self.run()

这是我的Pinger 课程:

class Pinger(threading.Thread):
    def __init__(self, address='', rate=1):
        threading.Thread.__init__(self)

        self.address = address
        self.ping_rate = rate
        self.ping_vector, self.last_ping = [], -1
        self.start_time, self.last_status = datetime.datetime.now(), []
        self.timestamp, self.time_vector = 0, [datetime.timedelta(0)] * 4

    def run(self):
            self.start_ping()

    def start_ping(self):
        self.timestamp = datetime.datetime.now()
        while True:
            ping_result = os.system('ping %s -n 1 >Null' % self.address)
            self.ping_vector.append(ping_result)

            if self.last_ping != ping_result:
                text = ['Reachable', 'Lost']
                print(str(self.timestamp)[:-4], self.address, text[ping_result])

            round_time_qouta = datetime.datetime.now() - self.timestamp
            self.timestamp = datetime.datetime.now()
            self.update_time_counter(ping_result, round_time_qouta)

            self.last_ping = ping_result
            time.sleep(self.ping_rate)

    def update_time_counter(self, ping_result=0, time_quota=datetime.timedelta(0)):
        """self.time_vector = [[cons.succ ping time],[cons.not_succ ping time],
        [max accum succ ping time],[max accum not_succ ping time] """

        p_vec = [0, 1]

        self.time_vector[p_vec[ping_result]] += time_quota
        if self.time_vector[p_vec[ping_result]].total_seconds() > self.time_vector[
            p_vec[ping_result] + 2].total_seconds():
            self.time_vector[p_vec[ping_result] + 2] = self.time_vector[p_vec[ping_result]]

        self.time_vector[p_vec[ping_result - 1]] = datetime.timedelta(0)

        self.last_status = [ping_result, self.chop_milisecond(self.time_vector[ping_result]),
                            self.chop_milisecond(self.time_vector[ping_result + 2]),
                            self.chop_milisecond(datetime.datetime.now() - self.start_time)]

        print(str(self.timestamp)[:-4], "State: " + ['Received', 'Lost'][ping_result],
              " Duration: " + self.last_status[1], " Max Duration: " + self.last_status[2],
              "Total time: " + self.last_status[3])

    def chop_milisecond(self, time):
        return str(time).split('.')[0]

【问题讨论】:

  • 使用threading.Event 通知您的线程何时应该退出,然后定期检查您的线程是否设置了事件并退出。
  • @zwer 你能用代码解释一下吗?

标签: python multithreading kill


【解决方案1】:

正如我在评论中所说,最简单的方法是使用threading.Event 在线程应该退出时发出信号。这样您就可以公开该事件并让其他线程设置它,同时您可以从您的线程中检查其状态并根据请求退出。

在你的情况下,它可能很简单:

class Pinger(threading.Thread):

    def __init__(self, address='', rate=1):
        threading.Thread.__init__(self)
        self.kill = threading.Event()
        # the rest of your setup...

    # etc.

    def start_ping(self):
        self.timestamp = datetime.datetime.now()
        while not self.kill.is_set():
            # do your pinging stuff

    # etc.

然后,当您希望线程停止时(例如从您的 UI 中),只需调用它:pinger_instance.kill.set(),您就完成了。请记住,由于阻塞 os.system() 调用以及您在 Pinger.start_ping() 方法末尾的 time.sleep(),它需要一些时间才能被杀死。

【讨论】:

    【解决方案2】:

    感谢@zwer 的领导。 这是我的完整代码(已标记更改)

    class Pinger(threading.Thread):
        def __init__(self, address='', rate=1):
            threading.Thread.__init__(self)
    
            self.address = address
            self.ping_rate = rate
            self.ping_vector, self.last_ping = [], -1
            self.start_time, self.last_status = datetime.datetime.now(), []
            self.timestamp, self.time_vector = 0, [datetime.timedelta(0)] * 4
            self.event = threading.Event() # <---- Added
    
        def run(self):
            while not self.event.is_set(): # <---- Added
                self.start_ping()
                self.event.wait(self.ping_rate) # <---- Added ( Time to repeat moved in here )
    
        def stop(self):       # <---- Added ( ease of use )
            self.event.set()  # <---- Added ( set to False and causes to stop )
    
    
        def start_ping(self):
            self.timestamp = datetime.datetime.now()
            # While loop ##--- > Deleted. now it loops in run method #####
            ping_result = os.system('ping %s -n 1 >Null' % self.address)
            self.ping_vector.append(ping_result)
    
            if self.last_ping != ping_result:
                text = ['Reachable', 'Lost']
                print(str(self.timestamp)[:-4], self.address, text[ping_result])
    
            round_time_qouta = datetime.datetime.now() - self.timestamp
            self.timestamp = datetime.datetime.now()
            self.update_time_counter(ping_result, round_time_qouta)
    
            self.last_ping = ping_result
            #### time.sleep (self.ping_rate)  # <---- deleted 
    
        def update_time_counter(self, ping_result=0, time_quota=datetime.timedelta(0)):
            """self.time_vector = [[cons.succ ping time],[cons.not_succ ping time],
            [max accum succ ping time],[max accum not_succ ping time] """
    
            p_vec = [0, 1]
    
            self.time_vector[p_vec[ping_result]] += time_quota
            if self.time_vector[p_vec[ping_result]].total_seconds() > self.time_vector[
                p_vec[ping_result] + 2].total_seconds():
                self.time_vector[p_vec[ping_result] + 2] = self.time_vector[p_vec[ping_result]]
    
            self.time_vector[p_vec[ping_result - 1]] = datetime.timedelta(0)
    
            self.last_status = [ping_result, self.chop_milisecond(self.time_vector[ping_result]),
                                self.chop_milisecond(self.time_vector[ping_result + 2]),
                                self.chop_milisecond(datetime.datetime.now() - self.start_time)]
    
            print(str(self.timestamp)[:-4], "State: " + ['Received', 'Lost'][ping_result],
                  " Duration: " + self.last_status[1], " Max Duration: " + self.last_status[2],
                  "Total time: " + self.last_status[3])
    
        def chop_milisecond(self, time):
            return str(time).split('.')[0]
    
        def get_status(self):
            return self.last_status
    
    
    c = Pinger('127.0.0.1', 5)
    c.start()
    time.sleep(10)
    c.stop()
    

    【讨论】:

    • 为什么不用事件 wait 替换 while 循环以减少 CPU 的占用?
    【解决方案3】:

    使用_Thread_stop():

    MyPinger._Thread__stop()

    【讨论】:

      【解决方案4】:

      我会对你的类进行一些不同的编码,以作为守护进程运行。

      保留 start_ping 代码并使用下一个代码:

      MyPinger = threading.Thread(target = self.start_ping, name="Pinger")
      MyPinger.setDaemon(True)
      MyPinger.start() # launch start_ping
      

      并且可以使用 _Thread_stop() 来阻止它,这有点野蛮......:

      if MyPinger.IsAlive():
         MyPinger._Thread__stop() 
      

      【讨论】:

        猜你喜欢
        • 2014-05-29
        • 2021-06-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-02-23
        • 1970-01-01
        • 2013-04-29
        • 1970-01-01
        相关资源
        最近更新 更多