Нужна помощь в программировании Python Thread - PullRequest
0 голосов
/ 10 мая 2011

Я разрабатываю пользовательский интерфейс, в котором есть кнопка «Выполнить» для запуска определенных тестов в командной строке. Я попытался реализовать потоки здесь для вызова командной строки и подумал о мониторинге потока.Пока тесты не запущены (в командной строке), я хочу, чтобы кнопка запуска была отключена, и хочу включить ее только при закрытой командной строке.

Я создал файл .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 ]

2 голосов
/ 10 мая 2011

Я бы почти рекомендовал не использовать поток, однако, если вы все еще хотите это сделать, один из очень простых способов связи между вашей основной программой и вашим потоком - через события потоков.На самом деле это просто логическое событие (включено или выключено), и вы можете действовать, когда событие установлено.Вот ваша оригинальная программа, обновленная для использования этого:

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().

[EDIT] Вот полностью рабочий пример, который я создал (вместо того, чтобы пытатьсядобавьте все в ваш образец):

Вот файл 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' в этом пакетном файле является жизненно важной, еслимы не говорим, что вызов подпроцесса никогда не прекратится.Надеюсь, этот пример поможет.

2 голосов
/ 10 мая 2011

Проблема в том, как вы контролируете поток. runscript блокирует программу, выполняя в цикле, пока поток жив, таким образом, блокируя систему событий GUI от обработки пользовательских событий - это создает впечатление "зависания", которое вы испытываете.

Существует много методов взаимодействия с потоками в программировании GUI и, в частности, PyQt. В таких случаях я предпочитаю использовать таймер. Как только вы запустите рабочий поток, также создайте таймер, который будет вызывать метод (слот) каждые 100 мс или около того. Этот метод таймера осуществляет мониторинг - проверяет, работает ли рабочий поток и т. Д. Этот не будет блокировать цикл событий по очевидным причинам.

...