需要Python线程编程方面的帮助

时间:2011-05-10 10:58:24

标签: python multithreading pyqt pyqt4

我正在开发一个UI,它有一个Run按钮,可以在命令提示符下运行某些测试。我尝试在这里实现线程来调用命令提示符并考虑监视线程。直到运行测试(在命令提示符下),我希望禁用运行按钮,并且只有在命令提示符关闭时才启用它。

我已经创建了一个.bat文件来在命令提示符下运行测试列表。

代码如下:

用于调用命令提示符的线程:

class RunMonitor(threading.Thread):
def run(self):
    print 'Invoking the command prompt .....'
    subprocess.call(["start", "/DC:\\Scripts", "scripts_to_execute.bat"], shell=True)

用于监控线程

def runscript(self):
    print 'Complete_file_Path inside Run script is : ' , self.complete_file_path
    file_operation.Generate_Bat_File(self.complete_file_path)

    run_monitor_object = RunMonitor()
    run_monitor_object.start()

    while True:
        if run_monitor_object.isAlive():
            print 'The thread is still alive....'
        else:
            print 'The Thread is not alive anymore'
            self.run_button.setEnabled(True)
            break

从上面的例子中,一旦我调用命令提示符,我运行一个while循环来监视状态,我希望只要调用命令提示符就会激活该线程,并且一旦关闭就会死掉命令提示符。但在我的情况下,应用程序只是挂起..

几个问题: 1.这是调用线程的正确方法吗? 2.这是监控线程状态的正确方法吗? 3.有没有更好的方法来解决这个问题?

对此的任何帮助将不胜感激。

感谢。

2 个答案:

答案 0 :(得分:2)

问题是你如何监控线程。只要线程处于活动状态,runscript就会通过循环执行来阻止程序,从而阻止GUI事件系统处理用户事件 - 这会产生你正在经历的“挂起”的外观。

在GUI编程和PyQt中有许多与线程交互的技术。在这种情况下,我更喜欢使用计时器。一旦启动工作线程,还要创建一个每100 ms左右调用一个方法(槽)的计时器。这个计时器方法进行监控 - 检查工作线程是否仍然存在等等。由于显而易见的原因,不会阻止事件循环。

答案 1 :(得分:2)

我几乎建议不要使用线程,但是,如果你仍然想要这样做,在主程序和线程之间进行通信的一种非常简单的方法是通过线程事件。这实际上只是一个布尔事件(打开或关闭),您可以在设置事件时执行操作。以下是您更新的原始程序以使用此功能:

class RunMonitor(threading.Thread): 
    def __init__(self, quit_event):
        threading.Thread.__init__(self)
        self.quit_event = quit_event
    def run(self):     
        print 'Invoking the command prompt .....'     
        subprocess.call(["start", "/DC:\\Scripts", "scripts_to_execute.bat"], shell=True)
        self.quit_event.set()

def runscript(self):     
    print 'Complete_file_Path inside Run script is : ' , self.complete_file_path     
    file_operation.Generate_Bat_File(self.complete_file_path)      

    quit_event = threading.Event()
    run_monitor_object = RunMonitor(quit_event).start()

    while True:         
        if not quit_event.is_set():
             print 'The thread is still alive....'         
        else:
             print 'The Thread is not alive anymore'             
             self.run_button.setEnabled(True)             
             break 

因此,基本上,在启动线程之前,您需要创建一个threading.Event()对象并将其传递给您的线程。一旦创建了这个事件,你可以.set()它'打开'事件,主程序只是等待它发生。

就像我说的,这很简单,它只是一个布尔事件。如果您需要更复杂的内容,可以添加更多活动,或者使用threading.Queue()代替。

[编辑] 以下是我创建的完整工作样本(而不是尝试将所有内容装入样本中):

这是python文件,请注意已更改为subprocess.call行:

import threading
import subprocess
import time

class RunMonitor(threading.Thread): 
    def __init__(self, quit_event):
        threading.Thread.__init__(self)
        self.quit_event = quit_event
    def run(self):     
        print 'Invoking the command prompt .....\n'   
        subprocess.call(["start", "/WAIT", "/DC:\\python27\\sample", "xxx12.bat"], shell=True)                
        self.quit_event.set()

class Something:
    def runscript(self):     
        print 'Starting the thread...'  

        quit_event = threading.Event()
        run_monitor_object = RunMonitor(quit_event).start()

        while True:         
            if not quit_event.is_set():
                 print 'The thread is still alive....'         
            else:
                 print 'The Thread is not alive anymore'             
                 break 
            time.sleep(1)

runme = Something()
runme.runscript()

请注意,我已在主循环中添加了一个睡眠,以便控制台不会填满“线程仍处于活动状态...”消息。

另外,这里的参考是我的批处理文件(我把它命名为xxx12.bat,在python代码中引用),我只是用它来导致延迟,所以我可以证明线程正确终止:

echo wscript.sleep 2500 > xxx12.vbs
start /wait xxx12.vbs
dir c:\
start /wait xxx12.vbs
dir c:\
start /wait xxx12.vbs
dir c:\
start /wait xxx12.vbs
dir c:\
start /wait xxx12.vbs
dir c:\
exit

这里要注意的重要一点是,这个批处理文件中的'exit'命令是至关重要的,如果我们不把它放在那里,那么子进程调用永远不会终止。希望这个例子能有所帮助。