Python:具有中断的后台进程



我有一个应用程序,它创建了一个带有按钮的GUI。每个按钮启动一个控制机器人的功能。我在一个单独的线程上运行这些函数,这样在主线程上运行的UI就不会被锁定。我想要一个";停止";按钮,它发送一个命令来停止机器人,但也会立即中断线程进程。

因为机器人的功能有很大的时间延迟和循环(几乎(无限期,例如

i = 0
while i<100
start motorA
time.sleep(120)
stop motorA
reverse motorA
time.sleep(120)
stop motor A
i += 1

我不能只是轮询是否将中断设置为true,或者可能需要120秒才能真正停止(足够长的时间让操作员点击更多按钮并将中断标志改回false…(

我的GUI事件循环当前如下所示:

while True:
event,values = window.read()
if event == "Button 1":
stop_all()
x = threading.Thread(target=function1, daemon=True)
x.start()

if event == "Button 2":
stop_all()
x = threading.Thread(target=function2, daemon=True)
x.start()

if event == "Stop":
stop_all()

有没有什么可以添加到stop_all((函数中,以立即中断线程"中运行的任何慢速循环函数;x〃;,还是我需要考虑使用多处理而不是线程?

干杯

多处理器而不是线程是一个更好的解决方案。代替:

x = threading.Thread(target = function1, daemon=True)

我使用:

x = multiprocessing.Process(target = function1, daemon=True)

我的停止功能就变成了:

def stop_all()
Stop motor
x.terminate()
x.join()

我只需要启动然后立即停止函数1;x〃;是在我尝试定义stop_all((之前定义的

实现这一点的一种方法是使用threading.Lock,并使用带有超时的threading.Lock.acquire来替换time.sleep

当您尝试在超时的情况下获取锁时(此时已获取锁(,它会等待超时到期,然后返回False。这种行为类似于time.sleep,但是如果在该"锁定"期间释放锁定;睡眠;时间,则立即返回True。类似地,如果在调用threading.Lock.acquire时锁已经被释放,那么它会立即返回True

下面实现的ThreadStopper类为管理锁的这个用例提供了一个更整洁的接口。

下面的示例演示了如何使用ThreadStopper类。该代码启动4个线程,每5秒打印一次内容,当您按下Enter键时,一个随机线程将立即停止,即使当前为"0";睡眠";。

请注意,每个线程都需要传递给它自己的ThreadStopper

import threading
import time
import random

class ThreadStopper:
def __init__(self):
self.lock = threading.Lock()
self.lock.acquire()
self.alive = True
def sleep(self, t):
if self.lock.acquire(timeout=t):
self.alive = False
def stop(self):
self.lock.release()
self.alive = False

num_threads = 4
thread_stoppers = []
threads = []

def worker(ts, i):
print(f'I am thread {i}')
while ts.alive:
print(f'Thread {i} looping')
ts.sleep(5) # ThreadStopper.sleep, not time.sleep
print(f'Thread {i} finished')

for i in range(num_threads):
thread_stopper = ThreadStopper()
# create the thread, passing the newly created ThreadStopper
thread = threading.Thread(target=worker, args=(thread_stopper, i))
thread.start()
thread_stoppers.append(thread_stopper)
threads.append(thread)
time.sleep(0.5)
running = set(range(num_threads))
while running:
input()  # wait for enter to be pressed
thread_to_stop = random.choice(list(running))
thread_stoppers[thread_to_stop].stop() # signal the ThreadStopper to stop
running.remove(thread_to_stop)
for thread in threads:
thread.join()

最新更新