如何构建代码以启动可以 kill/replace 彼此的任务
How to structure code to be able to launch tasks that can kill/replace each other
我有一个 Python 程序可以执行以下操作:
1) 无休止地等待 com 端口命令字符
2) 在字符接收时,启动一个新线程来执行一段特定的代码
如果收到新命令,我需要做的是:
1)杀死前一个线程
2) 推出新的
我在这里和那里读到这样做不是正确的方法。
知道我需要在同一进程中执行此操作的最佳方法是什么,所以我想我需要使用线程 ...
我建议您采用两种不同的方法:
- 如果您的进程都是从一个函数内部调用的,您可以set a timeout第一个函数。
- 如果您是 运行 外部脚本,您可能想要 kill the process.
可能想运行把串口放在一个单独的线程中。当它接收到一个字节时,将该字节放入队列中。让主程序循环并检查队列以决定如何处理它。在主程序中,您可以使用 join 终止线程并启动一个新线程。您可能还想查看线程池,看看它是否是您想要的。
ser = serial.Serial("COM1", 9600)
que = queue.Queue()
def read_serial(com, q):
val = com.read(1)
q.put(val)
ser_th = threading.Thread(target=read_serial, args=(ser, que))
ser_th.start()
th = None
while True:
if not que.empty():
val = que.get()
if val == b"e":
break # quit
elif val == b"a":
if th is not None:
th.join(0) # Kill the previous function
th = threading.Thread(target=functionA)
th.start()
elif val == b"b":
if th is not None:
th.join(0) # Kill the previous function
th = threading.Thread(target=functionB)
th.start()
elif val == b"c":
if th is not None:
th.join(0) # Kill the previous thread (functionA)
th = threading.Thread(target=functionC)
th.start()
try:
ser.close()
th.join(0)
except:
pass
如果您正在创建和加入很多线程,您可能只需要一个函数来检查 运行 的命令。
running = True
def run_options(option):
if option == 0:
print("Running Option 0")
elif option == 1:
print("Running Option 1")
else:
running = False
while running:
if not que.empty():
val = que.get()
run_options(val)
让我通过添加我的代码结构示例来尝试更准确地回答我的问题。
假设同步函数 A 仍然是 运行,因为在内部等待特定事件,如果收到命令 "c",我需要停止函数 A 并启动函数 C。
def functionA():
....
....
call a synchronous serviceA that can take several seconds even more to execute
....
....
def functionB():
....
....
call a synchronous serviceB that nearly returns immediately
....
....
def functionC():
....
....
call a synchronous serviceC
....
....
#-------------------
def launch_async_task(function):
t = threading.Thread(target=function, name="async")
t.setDaemon(True)
t.start()
#------main----------
while True:
try:
car = COM_port.read(1)
if car == "a":
launch_async_task(functionA)
elif car == "b":
launch_async_task(functionB)
elif car == "c":
launch_async_task(functionC)
好吧,我终于用了一段代码,使用ctypes lib来提供某种杀死线程的功能。
我知道这不是一个干净的方法,但在我的例子中,线程没有共享资源,所以它不应该有任何影响......
如果有帮助,下面是一段很容易在网上找到的代码:
def terminate_thread(thread):
"""Terminates a python thread from another thread.
:param thread: a threading.Thread instance
"""
if not thread.isAlive():
return
exc = ctypes.py_object(SystemExit)
res = ctypes.pythonapi.PyThreadState_SetAsyncExc(
ctypes.c_long(thread.ident), exc)
if res == 0:
raise ValueError("nonexistent thread id")
elif res > 1:
# """if it returns a number greater than one, you're in trouble,
# and you should call it again with exc=NULL to revert the effect"""
ctypes.pythonapi.PyThreadState_SetAsyncExc(thread.ident, None)
raise SystemError("PyThreadState_SetAsyncExc failed")
我有一个 Python 程序可以执行以下操作: 1) 无休止地等待 com 端口命令字符 2) 在字符接收时,启动一个新线程来执行一段特定的代码
如果收到新命令,我需要做的是: 1)杀死前一个线程 2) 推出新的
我在这里和那里读到这样做不是正确的方法。 知道我需要在同一进程中执行此操作的最佳方法是什么,所以我想我需要使用线程 ...
我建议您采用两种不同的方法:
- 如果您的进程都是从一个函数内部调用的,您可以set a timeout第一个函数。
- 如果您是 运行 外部脚本,您可能想要 kill the process.
可能想运行把串口放在一个单独的线程中。当它接收到一个字节时,将该字节放入队列中。让主程序循环并检查队列以决定如何处理它。在主程序中,您可以使用 join 终止线程并启动一个新线程。您可能还想查看线程池,看看它是否是您想要的。
ser = serial.Serial("COM1", 9600)
que = queue.Queue()
def read_serial(com, q):
val = com.read(1)
q.put(val)
ser_th = threading.Thread(target=read_serial, args=(ser, que))
ser_th.start()
th = None
while True:
if not que.empty():
val = que.get()
if val == b"e":
break # quit
elif val == b"a":
if th is not None:
th.join(0) # Kill the previous function
th = threading.Thread(target=functionA)
th.start()
elif val == b"b":
if th is not None:
th.join(0) # Kill the previous function
th = threading.Thread(target=functionB)
th.start()
elif val == b"c":
if th is not None:
th.join(0) # Kill the previous thread (functionA)
th = threading.Thread(target=functionC)
th.start()
try:
ser.close()
th.join(0)
except:
pass
如果您正在创建和加入很多线程,您可能只需要一个函数来检查 运行 的命令。
running = True
def run_options(option):
if option == 0:
print("Running Option 0")
elif option == 1:
print("Running Option 1")
else:
running = False
while running:
if not que.empty():
val = que.get()
run_options(val)
让我通过添加我的代码结构示例来尝试更准确地回答我的问题。
假设同步函数 A 仍然是 运行,因为在内部等待特定事件,如果收到命令 "c",我需要停止函数 A 并启动函数 C。
def functionA():
....
....
call a synchronous serviceA that can take several seconds even more to execute
....
....
def functionB():
....
....
call a synchronous serviceB that nearly returns immediately
....
....
def functionC():
....
....
call a synchronous serviceC
....
....
#-------------------
def launch_async_task(function):
t = threading.Thread(target=function, name="async")
t.setDaemon(True)
t.start()
#------main----------
while True:
try:
car = COM_port.read(1)
if car == "a":
launch_async_task(functionA)
elif car == "b":
launch_async_task(functionB)
elif car == "c":
launch_async_task(functionC)
好吧,我终于用了一段代码,使用ctypes lib来提供某种杀死线程的功能。 我知道这不是一个干净的方法,但在我的例子中,线程没有共享资源,所以它不应该有任何影响......
如果有帮助,下面是一段很容易在网上找到的代码:
def terminate_thread(thread):
"""Terminates a python thread from another thread.
:param thread: a threading.Thread instance
"""
if not thread.isAlive():
return
exc = ctypes.py_object(SystemExit)
res = ctypes.pythonapi.PyThreadState_SetAsyncExc(
ctypes.c_long(thread.ident), exc)
if res == 0:
raise ValueError("nonexistent thread id")
elif res > 1:
# """if it returns a number greater than one, you're in trouble,
# and you should call it again with exc=NULL to revert the effect"""
ctypes.pythonapi.PyThreadState_SetAsyncExc(thread.ident, None)
raise SystemError("PyThreadState_SetAsyncExc failed")