【问题标题】:Need Assistance in Python Thread programming在 Python 线程编程方面需要帮助
【发布时间】:2011-08-22 09:09:20
【问题描述】:

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

我创建了一个 .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.有没有更好的处理方法??

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

谢谢。

【问题讨论】:

  • 你为什么同时使用单独的线程和单独的子进程?一个子进程通常足以运行与您的 GUI 不同的东西。为什么还要使用单独的线程?
  • 我同意。但是我想监视子命令提示符,我怀疑它可以由子进程完成。正如我之前所说,我的 GUI 中有一个运行按钮,只有在命令提示符关闭时才能启用它。这可以不用线程实现吗?
  • @user596922:听起来您的问题应该是“如何监控单独的子进程的执行?”也许搜索“监控子流程”可能会有所帮助。 stackoverflow.com/questions/3869834/….

标签: python multithreading pyqt pyqt4


【解决方案1】:

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

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

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

【讨论】:

  • 上面的代码不起作用,因为while循环不允许程序调用命令提示符,应用程序只是挂起。只是好奇..它对你有用吗?
  • 我确实以一种简化的方式工作(我只是使用子进程来获取目录),但线程应该在 while 循环开始之前产生。您确定子流程调用正在自己工作吗?听起来这个过程要么没有开始,要么没有终止。您可以尝试在线程之外运行该调用以确保它正确终止吗?如果你仍然不能让它工作,我会用我的工作示例的完整代码添加另一个答案。
  • 其实我想我找到了你看到的问题,就是子进程调用。通过执行subprocess.call(["start", "/DC:\\Scripts", "scripts_to_execute.bat"], shell=True),“开始”会产生一个新的外壳,这似乎会导致子进程立即返回,而无需等待您的批处理文件完成。你可以试试:subprocess.call(["C:\\Scripts\\scripts_to_execute.bat"], shell=True) 吗?这应该强制子进程等到批处理文件完成后再发出完成信号。
  • 对不起所有额外的 cmets。我确实找到了一种在子进程命令中保留“开始”的方法。 subprocess.call(["start", "/WAIT", "/DC:\\Scripts", "scripts_to_execute.bat"], shell=True),但是,要使其正常工作,您需要确保批处理文件中的最后一个命令是“退出”。因此,当我在这里执行此操作时,批处理文件在一个新的命令会话中运行,与 python 会话分开。我将编辑我的原始答案将是完整的源代码。
【解决方案2】:

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

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

【讨论】:

  • 我浏览了 threading.timer 类,看起来我们可以调用一个只接受列表或字典作为参数的函数。我尝试传递我最初创建的线程的对象(用于调用命令提示符)但没有工作。线程 Thread-2 中的异常:回溯(最后一次调用):文件“C:\Python26\lib\threading.py”,第 532 行,在 __bootstrap_inner self.run() 文件“C:\Python26\WorkSpace\UI_Final\ src\main.py",第 41 行,在运行中 self.function(*self.args, **self.kwargs) TypeError: hello() argument after * must be a sequence, not RunMonitor
  • 不,使用 PyQt 的计时器,而不是 threading.Timer。 PyQt 的计时器触发可以绑定到插槽的信号 - 窗口类中的方法
  • 您好 Eli,我尝试使用计时器实现,但仍然没有成功。我能够在线程中调用命令提示符,并且能够对其进行监视,但是当命令提示符关闭时,我无法将其传达给我的主程序并且线程永远保持活动状态。我在这里错过了什么吗?代码的 sn-p 如下。
  • self.timer = QTimer() self.timer.connect(self.timer, SIGNAL("timeout()"),self.sendData) self.timer.start(1000) def sendData(self ): if self.run_timer: run_monitor_object = RunMonitor() print '正在启动线程............' run_monitor_object.start() if run_monitor_object.isRunning(): print '线程仍然活着.. .....' if run_monitor_object.isFinished(): print '线程不再活着......'
  • 请停止将大量代码粘贴到 cmets 中。这是不可读的。如果您对 qtimer 有疑问,请创建一个新问题并具体解释您不了解的内容
猜你喜欢
  • 2011-10-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-08
相关资源
最近更新 更多