Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/289.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在Python中停止循环线程?_Python_Multithreading_Wxpython - Fatal编程技术网

如何在Python中停止循环线程?

如何在Python中停止循环线程?,python,multithreading,wxpython,Python,Multithreading,Wxpython,告诉循环线程停止循环的正确方法是什么 我有一个相当简单的程序,可以在单独的threading.Thread类中ping指定的主机。在这个类中,它休眠60秒,然后再次运行,直到应用程序退出 我想在我的wx.Frame中实现一个“Stop”按钮来请求循环线程停止。它不需要立即结束线程,只要在醒来后停止循环即可 这是我的线程类(注意:我还没有实现循环,但它可能属于PingAssets中的run方法) 在我的wxPyhton框架中,我有一个从开始按钮调用的函数: def CheckAsset(self,

告诉循环线程停止循环的正确方法是什么

我有一个相当简单的程序,可以在单独的
threading.Thread
类中ping指定的主机。在这个类中,它休眠60秒,然后再次运行,直到应用程序退出

我想在我的
wx.Frame
中实现一个“Stop”按钮来请求循环线程停止。它不需要立即结束线程,只要在醒来后停止循环即可

这是我的
线程
类(注意:我还没有实现循环,但它可能属于PingAssets中的run方法)

在我的wxPyhton框架中,我有一个从开始按钮调用的函数:

def CheckAsset(self, asset):
        self.count += 1
        thread = PingAssets(self.count, asset, self)
        self.threads.append(thread)
        thread.start()

这在堆栈上以前被问过。请参阅以下链接:


基本上,您只需要使用stop函数设置线程,该函数设置线程将检查的sentinel值。在您的情况下,您将让循环中的某物检查sentinel值,看看它是否已更改,如果已更改,则循环可能会中断,线程可能会死亡。

我阅读了Stack上的其他问题,但在跨类通信时,我仍然有点困惑。以下是我的做法:

我使用一个列表来保存wxFrame类的
\uuuu init\uuuu
方法中的所有线程:
self.threads=[]

按照中的建议,在初始化线程类时,我在线程类中使用设置为
True
的信号

class PingAssets(threading.Thread):
    def __init__(self, threadNum, asset, window):
        threading.Thread.__init__(self)
        self.threadNum = threadNum
        self.window = window
        self.asset = asset
        self.signal = True

    def run(self):
        while self.signal:
             do_stuff()
             sleep()
我可以通过迭代线程来停止这些线程:

def OnStop(self, e):
        for t in self.threads:
            t.signal = False
螺纹可塞函数 您可以修改函数以允许 停在旗子旁边

我们需要一个运行函数可以访问的对象,我们为它设置停止运行的标志

我们可以使用
threading.currentThread()
对象

import threading
import time


def doit(arg):
    t = threading.currentThread()
    while getattr(t, "do_run", True):
        print ("working on %s" % arg)
        time.sleep(1)
    print("Stopping as you wish.")


def main():
    t = threading.Thread(target=doit, args=("task",))
    t.start()
    time.sleep(5)
    t.do_run = False
    

if __name__ == "__main__":
    main()
诀窍是,正在运行的线程可以附加其他属性。解决方案构建 根据假设:

  • 线程有一个属性“do_run”,默认值为
    True
  • 驱动父进程可以将属性“do_run”分配给已启动的线程,以
    False
运行代码时,我们得到以下输出:

$ python stopthread.py                                                        
working on task
working on task
working on task
working on task
working on task
Stopping as you wish.
药丸杀人-使用事件 另一种选择是使用
threading.Event
作为函数参数。是的 默认值
False
,但外部进程可以“设置它”(设置为
True
),函数可以 使用
等待(超时)
函数了解它

我们可以
等待
零超时,但我们也可以将其用作睡眠计时器(下面使用)

编辑:我在Python3.6中尝试过这个
stop\u event.wait()
在释放之前阻止事件(以及while循环)。它不返回布尔值。使用
stop\u event.is\u set()
代替

用一颗药丸停止多个线程 若我们必须停止多个线程,那个么杀戮药丸的优势就更明显了 立刻,因为一片药对所有人都有效

doit
根本不会改变,只有
main
处理线程的方式稍有不同

def main():
    pill2kill = threading.Event()
    tasks = ["task ONE", "task TWO", "task THREE"]

    def thread_gen(pill2kill, tasks):
        for task in tasks:
            t = threading.Thread(target=doit, args=(pill2kill, task))
            yield t

    threads = list(thread_gen(pill2kill, tasks))
    for thread in threads:
        thread.start()
    time.sleep(5)
    pill2kill.set()
    for thread in threads:
        thread.join()

我有一个不同的方法。我对线程类进行了子分类,并在构造函数中创建了一个事件对象。然后我编写了customjoin()方法,它首先设置此事件,然后调用其父版本的自身

这是我的课程,我在wxPython应用程序中用于串行端口通信:

import wx, threading, serial, Events, Queue

class PumpThread(threading.Thread):

    def __init__ (self, port, queue, parent):
        super(PumpThread, self).__init__()
        self.port = port
        self.queue = queue
        self.parent = parent

        self.serial = serial.Serial()
        self.serial.port = self.port
        self.serial.timeout = 0.5
        self.serial.baudrate = 9600
        self.serial.parity = 'N'

        self.stopRequest = threading.Event()

    def run (self):
        try:
            self.serial.open()
        except Exception, ex:
            print ("[ERROR]\tUnable to open port {}".format(self.port))
            print ("[ERROR]\t{}\n\n{}".format(ex.message, ex.traceback))
            self.stopRequest.set()
        else:
            print ("[INFO]\tListening port {}".format(self.port))
            self.serial.write("FLOW?\r")

        while not self.stopRequest.isSet():
            msg = ''
            if not self.queue.empty():
                try:
                    command = self.queue.get()
                    self.serial.write(command)
                except Queue.Empty:
                    continue

            while self.serial.inWaiting():
                char = self.serial.read(1)
                if '\r' in char and len(msg) > 1:
                    char = ''
                    #~ print('[DATA]\t{}'.format(msg))
                    event = Events.PumpDataEvent(Events.SERIALRX, wx.ID_ANY, msg)
                    wx.PostEvent(self.parent, event)
                    msg = ''
                    break
                msg += char
        self.serial.close()

    def join (self, timeout=None):
        self.stopRequest.set()
        super(PumpThread, self).join(timeout)

    def SetPort (self, serial):
        self.serial = serial

    def Write (self, msg):
        if self.serial.is_open:
            self.queue.put(msg)
        else:
            print("[ERROR]\tPort {} is not open!".format(self.port))

    def Stop(self):
        if self.isAlive():
            self.join()

队列用于向端口发送消息,主循环收回响应。我没有使用serial.readline()方法,因为不同的结束行字符,我发现io类的使用过于繁琐。

取决于在该线程中运行的内容。 如果这是您的代码,那么您可以实现停止条件(请参阅其他答案)

然而,如果您想要运行其他人的代码,那么您应该分叉并启动一个进程。像这样:

导入多处理
proc=multiprocessing.Process(target=your_proc_函数,args=())
程序启动()
现在,无论何时,只要您想停止该进程,请向其发送如下SIGTERM:

proc.terminate()
proc.join()
它并不慢:几分之一秒。 享受:)

我的解决方案是:

import threading, time

def a():
    t = threading.currentThread()
    while getattr(t, "do_run", True):
    print('Do something')
    time.sleep(1)

def getThreadByName(name):
    threads = threading.enumerate() #Threads list
    for thread in threads:
        if thread.name == name:
            return thread

threading.Thread(target=a, name='228').start() #Init thread
t = getThreadByName('228') #Get thread by name
time.sleep(5)
t.do_run = False #Signal to stop thread
t.join()

我发现从
threading.Thread
派生一个类来封装我的线程功能很有用。您只需在该类中重写的
run()
版本中提供自己的主循环。调用
start()
可以安排在单独的线程中调用对象的
run()
方法

在主循环内,定期检查是否设置了
线程.Event
。这样的事件是线程安全的

在这个类中,您有自己的
join()
方法,该方法在调用基类的
join()
方法之前设置停止事件对象。可以选择将时间值传递给基类的
join()
方法,以确保线程在短时间内终止

import threading
import time

class MyThread(threading.Thread):
    def __init__(self, sleep_time=0.1):
        self._stop_event = threading.Event()
        self._sleep_time = sleep_time
        """call base class constructor"""
        super().__init__()

    def run(self):
        """main control loop"""
        while not self._stop_event.isSet():
            #do work
            print("hi")
            self._stop_event.wait(self._sleep_time)

    def join(self, timeout=None):
        """set stop event and join within a given time period"""
        self._stop_event.set()
        super().join(timeout)


if __name__ == "__main__":
    t = MyThread()
    t.start()

    time.sleep(5)

    t.join(1) #wait 1s max

在检查
线程之前,在主循环内进行一次小的睡眠。事件
比连续循环占用的CPU更少。您可以有一个默认的睡眠时间(例如0.1s),但也可以在构造函数中传递该值。

回答得很好!帮助我解决了一个问题,假设我们设置了一个类似SIGALRM的内核信号,并在该信号的处理程序中使用您的方法(pill2kill.set,然后join)和sys.exit(0)停止进程和线程。1) 如果您运行应用程序并等待n秒,它可以正常工作2)如果您按ctrl+c,它可以正常工作3)但是,如果您按ctrl+z,然后等待几秒钟,然后按“fg”以恢复进程,如果SIGALRM的n秒已经过去,进程将停止,但线程会继续工作几毫秒。我有一段代码来证明这一点,你对此有什么想法吗?当我使用Thr时,我一直在寻找杀人药
import threading, time

def a():
    t = threading.currentThread()
    while getattr(t, "do_run", True):
    print('Do something')
    time.sleep(1)

def getThreadByName(name):
    threads = threading.enumerate() #Threads list
    for thread in threads:
        if thread.name == name:
            return thread

threading.Thread(target=a, name='228').start() #Init thread
t = getThreadByName('228') #Get thread by name
time.sleep(5)
t.do_run = False #Signal to stop thread
t.join()
import threading
import time

class MyThread(threading.Thread):
    def __init__(self, sleep_time=0.1):
        self._stop_event = threading.Event()
        self._sleep_time = sleep_time
        """call base class constructor"""
        super().__init__()

    def run(self):
        """main control loop"""
        while not self._stop_event.isSet():
            #do work
            print("hi")
            self._stop_event.wait(self._sleep_time)

    def join(self, timeout=None):
        """set stop event and join within a given time period"""
        self._stop_event.set()
        super().join(timeout)


if __name__ == "__main__":
    t = MyThread()
    t.start()

    time.sleep(5)

    t.join(1) #wait 1s max