Python,停止线程
Python, Stop a Thread
我正在尝试创建一个 class 来 ping 一个 IP 地址并记录连接/未连接的时间。
由于此 class 是 GUI 的一部分,我希望在用户询问时停止此线程。
找到了一些对这个问题进行重新分级的问答,但没有一个真正导致线程停止。
我正在尝试制作一种方法,这是 class 的一部分,它将停止 self.run()
这是我的 Pinger
class:
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]
使用_Thread_stop():
MyPinger._Thread__stop()
我会对您的 class 进行一些不同的编码,将 运行 作为守护进程。
保留 start_ping 代码并使用下一个代码:
MyPinger = threading.Thread(target = self.start_ping, name="Pinger")
MyPinger.setDaemon(True)
MyPinger.start() # launch start_ping
并且可以使用 _Thread_stop() 来阻止它,这有点粗暴...:[=12=]
if MyPinger.IsAlive():
MyPinger._Thread__stop()
正如我在评论中所说,最简单的方法是使用 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()
,它需要一些时间才能被杀死。
感谢@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()
我正在尝试创建一个 class 来 ping 一个 IP 地址并记录连接/未连接的时间。
由于此 class 是 GUI 的一部分,我希望在用户询问时停止此线程。
找到了一些对这个问题进行重新分级的问答,但没有一个真正导致线程停止。
我正在尝试制作一种方法,这是 class 的一部分,它将停止 self.run()
这是我的 Pinger
class:
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]
使用_Thread_stop():
MyPinger._Thread__stop()
我会对您的 class 进行一些不同的编码,将 运行 作为守护进程。
保留 start_ping 代码并使用下一个代码:
MyPinger = threading.Thread(target = self.start_ping, name="Pinger")
MyPinger.setDaemon(True)
MyPinger.start() # launch start_ping
并且可以使用 _Thread_stop() 来阻止它,这有点粗暴...:[=12=]
if MyPinger.IsAlive():
MyPinger._Thread__stop()
正如我在评论中所说,最简单的方法是使用 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()
,它需要一些时间才能被杀死。
感谢@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()