如何终止 Python 中的线程?
How to terminate a thread in Python?
我知道这个话题已经被讨论过几次了,但是我已经尝试过,或者至少尝试了几乎所有的解决方案,但是作为一个相当新的 python basher,我无法获得以前的任何一个工作解决方案。
脚本的基本前提是它订阅了一个 MQTT 代理并等待命令,单个操作命令 100% 有效,但是其中一个命令需要无限期地循环到 运行 直到另一个命令收到,因此最合适的解决方案是在单独的线程中 运行 "loop",而主订阅者循环继续 "listen" 以获取下一个命令。
一切正常 95%,"static" 命令通过,任务 运行 正常,然后当 "mtg" 命令通过时,它会触发线程和循环 运行s 100%,但是这是它失败的地方,当收到下一个命令时,我可以确认 "if" 语句在将消息打印到控制台时处理命令,但是 thread.stop() 不是 运行,也可能是 运行,但它不会终止线程 --- 我正在努力弄清楚。
一些代码:
from sys import exit
import blinkt
import threading
import time
MQTT_SERVER = '192.168.x.x'
MQTT_PORT = 1883
MQTT_TOPIC = 'mytopic'
REDS = [0, 0, 0, 0, 0, 16, 64, 255, 64, 16, 0, 0, 0, 0, 0, 0]
start_time = time.time()
class task(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.kill = threading.Event()
self.event = threading.Event()
self._stop = threading.Event()
def run(self):
# while not self.kill.is_set():
while True:
if self.stopped():
return
self.start_run()
def stop(self):
# self.event.set()
self._stop.set()
def stopped(self):
return self._stop.isSet()
def start_run(self):
# while True: <-- no longer needed as the run method loops the process.
delta = (time.time() - start_time) * 16
offset = int(abs((delta % len(REDS)) - blinkt.NUM_PIXELS))
for i in range(blinkt.NUM_PIXELS):
blinkt.set_pixel(i, REDS[offset + i], 0, 0)
blinkt.show()
time.sleep(0.1)
def on_connect(client, userdata, flags, rc):
print('Connected with result code ' + str(rc))
client.subscribe(MQTT_TOPIC)
def on_message(client, userdata, msg):
data = msg.payload
if type(data) is bytes:
data = data.decode('utf-8')
data = data.split(',')
command = data.pop(0)
if command == 'clr' and len(data) == 0:
blinkt.clear()
blinkt.show()
t1.stop() #<--- I've tried a few ways to get the task to stop when the "clr" command is recieved
task.stop()
return
if command == 'rgb' and len(data) == 4: #<-- This code block works fine, msg arrives and LEDs are set correctly
try:
pixel = data.pop(0)
if pixel == '*':
pixel = None
else:
pixel = int(pixel)
if pixel > 7:
print('Pixel out of range: ' + str(pixel))
return
r, g, b = [int(x) & 0xff for x in data]
print(command, pixel, r, g, b)
except ValueError:
print('Malformed command: ' + str(msg.payload))
return
if pixel is None:
for x in range(blinkt.NUM_PIXELS):
blinkt.set_pixel(x, r, g, b)
else:
blinkt.set_pixel(pixel, r, g, b)
blinkt.show()
return
if command == 'mtg' and len(data) == 0:
print(command)
t1 = task()
t1.start() #<-- Here is where the Thread is called to start and seems to run ok
return
blinkt.set_clear_on_exit()
client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message
client.connect(MQTT_SERVER, MQTT_PORT, 60)
client.loop_forever()
您的 t1
变量是局部变量,因此当您退出 on_message
函数时它会丢失。此外,您将 class task
和实例 t1
混为一谈(task.stop()
将不起作用)。
为了快速修复,将 t1 = None
声明为全局变量,然后将 global t1
添加到您的 on_message
函数...
但是,我会考虑重构一些东西,这样就有一个总是 运行 的线程来命令 Blinkt!,并且 MQTT 消息处理程序只是相应地设置它的状态——就像这样。显然是干编码,所以可能有些愚蠢。
from sys import exit
import blinkt
import threading
import time
MQTT_SERVER = "192.168.x.x"
MQTT_PORT = 1883
MQTT_TOPIC = "mytopic"
REDS = [0, 0, 0, 0, 0, 16, 64, 255, 64, 16, 0, 0, 0, 0, 0, 0]
start_time = time.time()
class BlinktManager(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.stop_event = threading.Event()
self.mode = None
def run(self):
while not self.stop_event.isSet():
self.tick()
self.stop_event.wait(0.1) # instead of sleep
def tick(self):
if self.mode == "reds":
self._tick_reds()
def _tick_reds(self):
delta = (time.time() - start_time) * 16
offset = int(
abs((delta % len(REDS)) - blinkt.NUM_PIXELS)
)
for i in range(blinkt.NUM_PIXELS):
blinkt.set_pixel(i, REDS[offset + i], 0, 0)
blinkt.show()
def clear(self):
self.mode = None
blinkt.clear()
blinkt.show()
def set_all_pixels(self, r, g, b):
self.mode = None
for x in range(blinkt.NUM_PIXELS):
blinkt.set_pixel(x, r, g, b)
blinkt.show()
def set_pixel(self, x, r, g, b):
self.mode = None
blinkt.set_pixel(x, r, g, b)
blinkt.show()
def begin_reds(self):
self.mode = "reds"
def on_connect(client, userdata, flags, rc):
print("Connected with result code " + str(rc))
client.subscribe(MQTT_TOPIC)
def on_message(client, userdata, msg):
data = msg.payload
if type(data) is bytes:
data = data.decode("utf-8")
data = data.split(",")
command = data.pop(0)
if command == "clr" and len(data) == 0:
blinkt_manager.clear()
if command == "rgb" and len(data) == 4:
x = data[0]
r, g, b = [int(x) & 0xFF for x in data[1:]]
if x == "*":
blinkt_manager.set_all_pixels(r, g, b)
else:
# TODO: error handling
blinkt_manager.set_pixel(int(x), r, g, b)
if command == "mtg" and len(data) == 0:
blinkt_manager.begin_reds()
blinkt.set_clear_on_exit()
blinkt_manager = BlinktManager()
blinkt_manager.start()
client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message
client.connect(MQTT_SERVER, MQTT_PORT, 60)
client.loop_forever()
Python节目募集
python 中的异常
线程
import threading
import ctypes
import time
class thread_with_exception(threading.Thread):
def __init__(self, name):
threading.Thread.__init__(self)
self.name = name
def run(self):
# target function of the thread class
try:
while True:
print('running ' + self.name)
finally:
print('ended')
def get_id(self):
# returns id of the respective thread
if hasattr(self, '_thread_id'):
return self._thread_id
for id, thread in threading._active.items():
if thread is self:
return id
def raise_exception(self):
thread_id = self.get_id()
res = ctypes.pythonapi.PyThreadState_SetAsyncExc(thread_id,
ctypes.py_object(SystemExit))
if res > 1:
ctypes.pythonapi.PyThreadState_SetAsyncExc(thread_id, 0)
print('Exception raise failure')
t1 = thread_with_exception('Thread 1')
t1.start()
time.sleep(2)
t1.raise_exception()
t1.join()
我知道这个话题已经被讨论过几次了,但是我已经尝试过,或者至少尝试了几乎所有的解决方案,但是作为一个相当新的 python basher,我无法获得以前的任何一个工作解决方案。
脚本的基本前提是它订阅了一个 MQTT 代理并等待命令,单个操作命令 100% 有效,但是其中一个命令需要无限期地循环到 运行 直到另一个命令收到,因此最合适的解决方案是在单独的线程中 运行 "loop",而主订阅者循环继续 "listen" 以获取下一个命令。
一切正常 95%,"static" 命令通过,任务 运行 正常,然后当 "mtg" 命令通过时,它会触发线程和循环 运行s 100%,但是这是它失败的地方,当收到下一个命令时,我可以确认 "if" 语句在将消息打印到控制台时处理命令,但是 thread.stop() 不是 运行,也可能是 运行,但它不会终止线程 --- 我正在努力弄清楚。
一些代码:
from sys import exit
import blinkt
import threading
import time
MQTT_SERVER = '192.168.x.x'
MQTT_PORT = 1883
MQTT_TOPIC = 'mytopic'
REDS = [0, 0, 0, 0, 0, 16, 64, 255, 64, 16, 0, 0, 0, 0, 0, 0]
start_time = time.time()
class task(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.kill = threading.Event()
self.event = threading.Event()
self._stop = threading.Event()
def run(self):
# while not self.kill.is_set():
while True:
if self.stopped():
return
self.start_run()
def stop(self):
# self.event.set()
self._stop.set()
def stopped(self):
return self._stop.isSet()
def start_run(self):
# while True: <-- no longer needed as the run method loops the process.
delta = (time.time() - start_time) * 16
offset = int(abs((delta % len(REDS)) - blinkt.NUM_PIXELS))
for i in range(blinkt.NUM_PIXELS):
blinkt.set_pixel(i, REDS[offset + i], 0, 0)
blinkt.show()
time.sleep(0.1)
def on_connect(client, userdata, flags, rc):
print('Connected with result code ' + str(rc))
client.subscribe(MQTT_TOPIC)
def on_message(client, userdata, msg):
data = msg.payload
if type(data) is bytes:
data = data.decode('utf-8')
data = data.split(',')
command = data.pop(0)
if command == 'clr' and len(data) == 0:
blinkt.clear()
blinkt.show()
t1.stop() #<--- I've tried a few ways to get the task to stop when the "clr" command is recieved
task.stop()
return
if command == 'rgb' and len(data) == 4: #<-- This code block works fine, msg arrives and LEDs are set correctly
try:
pixel = data.pop(0)
if pixel == '*':
pixel = None
else:
pixel = int(pixel)
if pixel > 7:
print('Pixel out of range: ' + str(pixel))
return
r, g, b = [int(x) & 0xff for x in data]
print(command, pixel, r, g, b)
except ValueError:
print('Malformed command: ' + str(msg.payload))
return
if pixel is None:
for x in range(blinkt.NUM_PIXELS):
blinkt.set_pixel(x, r, g, b)
else:
blinkt.set_pixel(pixel, r, g, b)
blinkt.show()
return
if command == 'mtg' and len(data) == 0:
print(command)
t1 = task()
t1.start() #<-- Here is where the Thread is called to start and seems to run ok
return
blinkt.set_clear_on_exit()
client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message
client.connect(MQTT_SERVER, MQTT_PORT, 60)
client.loop_forever()
您的 t1
变量是局部变量,因此当您退出 on_message
函数时它会丢失。此外,您将 class task
和实例 t1
混为一谈(task.stop()
将不起作用)。
为了快速修复,将 t1 = None
声明为全局变量,然后将 global t1
添加到您的 on_message
函数...
但是,我会考虑重构一些东西,这样就有一个总是 运行 的线程来命令 Blinkt!,并且 MQTT 消息处理程序只是相应地设置它的状态——就像这样。显然是干编码,所以可能有些愚蠢。
from sys import exit
import blinkt
import threading
import time
MQTT_SERVER = "192.168.x.x"
MQTT_PORT = 1883
MQTT_TOPIC = "mytopic"
REDS = [0, 0, 0, 0, 0, 16, 64, 255, 64, 16, 0, 0, 0, 0, 0, 0]
start_time = time.time()
class BlinktManager(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.stop_event = threading.Event()
self.mode = None
def run(self):
while not self.stop_event.isSet():
self.tick()
self.stop_event.wait(0.1) # instead of sleep
def tick(self):
if self.mode == "reds":
self._tick_reds()
def _tick_reds(self):
delta = (time.time() - start_time) * 16
offset = int(
abs((delta % len(REDS)) - blinkt.NUM_PIXELS)
)
for i in range(blinkt.NUM_PIXELS):
blinkt.set_pixel(i, REDS[offset + i], 0, 0)
blinkt.show()
def clear(self):
self.mode = None
blinkt.clear()
blinkt.show()
def set_all_pixels(self, r, g, b):
self.mode = None
for x in range(blinkt.NUM_PIXELS):
blinkt.set_pixel(x, r, g, b)
blinkt.show()
def set_pixel(self, x, r, g, b):
self.mode = None
blinkt.set_pixel(x, r, g, b)
blinkt.show()
def begin_reds(self):
self.mode = "reds"
def on_connect(client, userdata, flags, rc):
print("Connected with result code " + str(rc))
client.subscribe(MQTT_TOPIC)
def on_message(client, userdata, msg):
data = msg.payload
if type(data) is bytes:
data = data.decode("utf-8")
data = data.split(",")
command = data.pop(0)
if command == "clr" and len(data) == 0:
blinkt_manager.clear()
if command == "rgb" and len(data) == 4:
x = data[0]
r, g, b = [int(x) & 0xFF for x in data[1:]]
if x == "*":
blinkt_manager.set_all_pixels(r, g, b)
else:
# TODO: error handling
blinkt_manager.set_pixel(int(x), r, g, b)
if command == "mtg" and len(data) == 0:
blinkt_manager.begin_reds()
blinkt.set_clear_on_exit()
blinkt_manager = BlinktManager()
blinkt_manager.start()
client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message
client.connect(MQTT_SERVER, MQTT_PORT, 60)
client.loop_forever()
Python节目募集 python 中的异常 线程
import threading
import ctypes
import time
class thread_with_exception(threading.Thread):
def __init__(self, name):
threading.Thread.__init__(self)
self.name = name
def run(self):
# target function of the thread class
try:
while True:
print('running ' + self.name)
finally:
print('ended')
def get_id(self):
# returns id of the respective thread
if hasattr(self, '_thread_id'):
return self._thread_id
for id, thread in threading._active.items():
if thread is self:
return id
def raise_exception(self):
thread_id = self.get_id()
res = ctypes.pythonapi.PyThreadState_SetAsyncExc(thread_id,
ctypes.py_object(SystemExit))
if res > 1:
ctypes.pythonapi.PyThreadState_SetAsyncExc(thread_id, 0)
print('Exception raise failure')
t1 = thread_with_exception('Thread 1')
t1.start()
time.sleep(2)
t1.raise_exception()
t1.join()