Python/Tkinter: итерации цикла не завершаются

В следующем случае я пытаюсь напечатать весь вывод сценария temp2 (который выполняется через подпроцесс) в виджет текстового поля в режиме реального времени.

Проблема, с которой я столкнулся, заключается в том, что в temp2 для i <= 468 скрипт работает нормально, и мне кажется, что это в реальном времени.

Однако, если я поставлю i = 469 или выше, выполнение остановится после многих итераций без завершения.

Так, например, для i = 469 файл журнала содержит записи от i = 469 до i = 3. Там после всего процесс останавливается.

Обратите внимание: значение i = 469 может не совпадать с вашим компьютером. Если вам подходит i = 469, попробуйте более высокое значение.

Temp1.py — основной скрипт.

#temp1.py
from Tkinter import *
import Tkinter as tk
import os
import ttk 
os.system('echo OS ready')
os.system('chmod 755 *')
import subprocess
import sys

#Creating new Window to display output 
t = Tk()
t.title('output Run Display')
t.geometry('800x1000-5+40')
t.state('normal')
little = Label(t, text="NRUNTEST OUTPUT LOG").grid(column = 0, row = 0)
log = Text(t, state='disabled', width=115, height=150, wrap='none')
log.grid(row = 1, column = 0)

test=subprocess.Popen('temp2',shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)


#stdout
while True:
    line_out = test.stdout.readline()
    line_er  = test.stderr.readline()
    if line_out == "" and line_er == "":
        break
    else:
        log['state'] = 'normal'
        log.insert('end', line_out)
        log.insert('end', line_er)
        log['state'] = 'disabled'
        print line_out
        print line_er
        t.update()
t.mainloop()

И ниже сценарий, который я запускаю через подпроцесс.

#temp2 #csh script

set i = 469
while ($i > 0)
  echo i is $i | tee -a log
  set i = `expr "$i" - 1`
end 

person Ani    schedule 28.11.2011    source источник
comment
Правильный ли отступ в строке else:? Также строки ниже кажутся недействительными...   -  person eumiro    schedule 28.11.2011
comment
В моем интерпретаторе все было в порядке, здесь исправлены некоторые ошибки отступов из-за копирования-вставки с unix на windows машину   -  person Ani    schedule 28.11.2011


Ответы (2)


Ваша проблема в том, что вызов test.stdout.readline блокируется, что означает, что обработка остановится на этом и возобновится только тогда, когда появится новая строка доступных данных, которая будет возвращена.

То же самое верно и для test.stderr.readline, конечно.

Я думаю, что самый простой способ справиться с тем, что вы хотите, - это записать ваш подпроцесс в файл в файловой системе, открыть этот файл в своем основном процессе и попытаться прочитать его внутри функции обратного вызова tkinter, регулярно вызываемой с помощью метода .after tkinter .

(с файлом в файловой системе вы можете использовать методы seek и tell, чтобы проверить, находитесь ли вы в конце файла)

Обратите внимание, что в коде, который вы разместили в качестве примера, ваш вызов Tkinter.mainloop достигается только после того, как подпроцесс уже исчерпан.

Еще лучшим решением было бы читать нужные вам журналы полностью на Python, не полагаясь на сценарий оболочки.

Tkinter.after похож на settimeout javascript — это метод для виджета (скажем, вашего объекта «t»), и вы передаете ему количество миллисекунд ожидания и имя вызываемой функции —

как в

def verify_output():
    # read subprocess output file and update the window if needed
    ...
    # call self after 1 second
    t.after(1000, verify_output)

# callreader callback for the first time:

t.after(10, verify_output)
Tkinter.mainloop()
person jsbueno    schedule 28.11.2011

Как отвечает jsbueno, проблема возникает из-за блокировки вызова readline. Вместо этого вы можете использовать источник событий файла, чтобы получать уведомления, когда данные доступны (через метод createfilehandler tkinter). Подробнее см. предыдущий ответ.

person FabienAndre    schedule 08.12.2011