2011-02-09 36 views
15

Tôi muốn bắt đầu một chương trình cần vài phút để hoàn tất. Trong thời gian này, tôi muốn đọc thông báo tiến độ của chương trình (được in trên stdout). Vấn đề là tôi không thể tìm ra cách đọc đầu ra của nó trong khi chạy.Nhận thông báo tiến bộ từ một tiến trình con

Chức năng duy nhất tôi tìm thấy để đọc đầu ra của chương trình là Popen.communicate(), nhưng phương pháp này chờ cho đến khi quá trình kết thúc. Vì vậy, nó là không thể có được sự tiến bộ và làm cho nó có thể nhìn thấy cho người sử dụng trong một cách định dạng đặc biệt.

Có thể thực hiện điều này theo cách khác không?

Khi tôi chạy quy trình với subprocess.popen bằng tập lệnh của mình, tôi thấy đầu ra của chương trình trên màn hình. Có thể giấu nó không? (Ubuntu 10.10, thiết bị đầu cuối thông thường)

Trả lời

15

Đơn giản nhất là gọi Popen bằng đối số từ khóa stdout=subprocess.PIPE.

p = subprocess.Popen(["ls"], stdout=subprocess.PIPE) 
while True: 
    line = p.stdout.readline() 
    if not line: 
     break 
    print line 

Để thấy điều này trong hành động, đây là hai kịch bản mẫu. Làm cho họ cả trong cùng thư mục và chạy python superprint.py

printandwait.py:

import time 
import sys 
print 10 
sys.stdout.flush() 
time.sleep(10) 
print 20 
sys.stdout.flush() 

superprint.py:

import subprocess 
import sys 
p = subprocess.Popen(["python printandwait.py"], shell=True, stdout=subprocess.PIPE) 
while True: 
    print "Looping" 
    line = p.stdout.readline() 
    if not line: 
     break 
    print line.strip() 
    sys.stdout.flush() 
+0

Điều gì sẽ xảy ra nếu một số dữ liệu đến sau khi bạn đã phá vỡ vòng lặp while? – Neo

+1

@Neo: ví dụ của anh ấy vi phạm tại EOF, điều đó có nghĩa là không có thêm dữ liệu nào có thể đến sau đó. NHƯNG, để trả lời ý nghĩa của câu hỏi của bạn: nếu bạn không tiếp tục đọc đường ống stdout, bộ đệm có thể lấp đầy và tiến trình con sẽ chặn cố gắng viết stdout. – payne

+0

Nó sẽ chờ bạn trong p.stdout để sử dụng sau này. Tuy nhiên, cuộc gọi readline sẽ chặn cho đến khi đầu vào mới đến hoặc đường ống đóng. Đã thêm một số tập lệnh mẫu. – chmullig

2

Bạn có thể thực hiện cuộc thăm dò ý kiến ​​về trạng thái của quy trình con và giữ các đường xuất.

p = subprocess.Popen('ls;sleep 10', shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 

rc = p.poll() 
while rc != 0: 
    while True: 
     line = p.stdout.readline() 
     if not line: 
      break 
     print line 
    rc = p.poll() 

assert rc == 0 
1

Đó chắc chắn có thể: gói của tôi python-gnupg thực hiện chính xác này, đẻ trứng gpg (Gnu Privacy Guard) trong một tiến trình con. Trong trường hợp chung, bạn cần phải chỉ định subprocess.PIPE cho stdout subprocess và stderr; sau đó tạo ra hai chủ đề riêng biệt mà đọc stdout subprocess và stderr đến bất cứ nơi nào bạn muốn.

Trong trường hợp python-gnupg, thông báo trạng thái từ gpg được đọc và hành động trong khi quá trình gpg đang chạy (không đợi cho đến khi hoàn tất).

Về cơ bản, giả là

process = subprocess.Popen(..., stdout=subprocess.PIPE, stderr=subprocess.PIPE) 
stderr = process.stderr 
rr = threading.Thread(target=response_reader_func, args=(process.stderr,)) 
rr.setDaemon(True) 
rr.start() 

dr = threading.Thread(target=data_reader_func, args=(process.stdout,)) 
dr.setDaemon(True) 
dr.start() 

dr.join() 
rr.join() 
process.wait() 

Các chức năng đọc thường phương pháp của một lớp kèm theo đó làm điều đúng dựa trên những gì họ đang đọc (trong trường hợp của bạn, cập nhật thông tin tiến bộ một cách nào đó).

Các vấn đề liên quan