2010-08-03 17 views
5

Tôi muốnpython: cách tiếp cận đơn giản để giết trẻ em hoặc báo cáo thành công của chúng?

  1. lệnh shell cuộc gọi (ví dụ 'ngủ' bên dưới) song song,
  2. Báo cáo tình hình khởi động cá nhân của họ và hoàn tất và
  3. có thể giết chúng với 'kill -9 parent_process_pid '.

Đã có rất nhiều văn bản về những thứ này nhưng tôi cảm thấy mình chưa tìm thấy giải pháp pythonic tao nhã mà tôi đang tìm kiếm. Tôi cũng đang cố giữ những thứ tương đối dễ đọc (và viết tắt) cho một người hoàn toàn không quen với python.

Tiếp cận của tôi cho đến nay (xem mã bên dưới) đã được:

  1. đặt subprocess.call (unix_command) trong một chức năng wrapper rằng báo cáo khi bắt đầu và kết thúc của lệnh.
  2. gọi hàm bao bọc bằng đa xử lý. Xử lý.
  3. theo dõi các khay thích hợp, lưu trữ chúng trên toàn cầu và tiêu diệt chúng trong signal_handler.

Tôi đã cố gắng tránh một giải pháp định kỳ thăm dò ý kiến ​​các quy trình nhưng tôi không chắc chắn tại sao.

Có cách tiếp cận nào tốt hơn không?

import subprocess,multiprocessing,signal 
import sys,os,time 

def sigterm_handler(signal, frame): 
     print 'You killed me!' 
     for p in pids: 
       os.kill(p,9) 
     sys.exit(0) 

def sigint_handler(signal, frame): 
     print 'You pressed Ctrl+C!' 
     sys.exit(0) 

signal.signal(signal.SIGINT, sigint_handler) 
signal.signal(signal.SIGTERM, sigterm_handler) 

def f_wrapper(d): 
     print str(d) + " start" 
     p=subprocess.call(["sleep","100"]) 
     pids.append(p.pid) 
     print str(d) + " done" 

print "Starting to run things." 

pids=[] 

for i in range(5): 
     p=multiprocessing.Process(target=f_wrapper,args=(i,)) 
     p.daemon=True 
     p.start() 

print "Got things running ..." 

while pids: 
     print "Still working ..." 
     time.sleep(1) 
+8

+1 cho tiêu đề nhận được sự chú ý. –

+1

Tôi không biết rằng Python có khả năng giết chết trẻ em ... –

+0

@ Zonda333: Ồ, chắc chắn rồi. 'từ __future__ giết người nhập khẩu'. –

Trả lời

4

Khi subprocess.call lợi nhuận, các tiểu trình được thực hiện - và giá trị trả call 's là các tiểu trình của returncode. Vì vậy, tích lũy các mã trả về đó trong danh sách pids (mà btw không được đồng bộ hóa giữa quá trình đa bổ sung nó và quy trình "chính") và gửi các tín hiệu 9 "như thể" chúng là id quá trình thay vì mã trả về. sai rồi.

Một điều với câu hỏi đó là chắc chắn sai là spec:

có thể giết chúng với 'kill -9 parent_process_pid'.

kể từ khi có nghĩa là quá trình cha mẹ có thể không có khả năng đánh chặn các tín hiệu (đó là mục đích chỉ định một cách rõ ràng) - Tôi tưởng tượng Do đó, giả mạo ở đây.

Bạn nên sử dụng threading thay vì multiprocessing (mỗi chủ đề "người giữ trẻ" hoặc quy trình, về cơ bản không có gì ngoài chờ quy trình phụ của nó, vậy tại sao quá trình xử lý trên một tác vụ nhẹ như vậy?); bạn cũng nên gọi suprocess.Process trong chủ đề chính (để bắt đầu quá trình con và có thể lấy được .pid để đưa vào danh sách) và chuyển đối tượng quá trình kết quả đến chuỗi giữ trẻ đang đợi (và khi báo cáo xong và xóa nó khỏi danh sách). Danh sách các id subprocess nên được bảo vệ bởi một khóa, vì thread chính và một số chủ đề giữ trẻ có thể truy cập nó, và một bộ có lẽ sẽ là một lựa chọn tốt hơn so với danh sách (xóa nhanh hơn) vì bạn không quan tâm về tránh trùng lặp.

Vì vậy, khoảng (không có thử nghiệm, vì vậy có thể có lỗi ;-) Tôi muốn thay đổi mã của bạn để s/điều như:

import subprocess, threading, signal 
import sys, time 

pobs = set() 
pobslock = threading.Lock() 
def numpobs(): 
    with pobslock: 
     return len(pobs) 

def sigterm_handler(signal, frame): 
    print 'You killed me!' 
    with pobslock: 
     for p in pobs: p.kill() 
    sys.exit(0) 

def sigint_handler(signal, frame): 
    print 'You pressed Ctrl+C!' 
    sys.exit(0) 

signal.signal(signal.SIGINT, sigint_handler) 
signal.signal(signal.SIGTERM, sigterm_handler) 

def f_wrapper(d, p): 
    print d, 'start', p.pid 
    rc = p.wait() 
    with pobslock: 
     pobs.remove(p) 
    print d, 'done, rc =', rc 

print "Starting to run things." 

for i in range(5): 
    p = subprocess.Popen(['sleep', '100']) 
    with pobslock: 
     pobs.add(p) 
    t = threading.Thread(target=f_wrapper, args=(i, p)) 
    t.daemon=True 
    t.start() 

print "Got things running ..." 

while numpobs(): 
    print "Still working ..." 
    time.sleep(1) 
+0

Cảm ơn, điều đó rất hữu ích. Tôi sẽ đăng lại khi tôi dọn dẹp! – mathtick

+0

@mathtick, bạn được chào đón! Tôi đã chỉnh sửa chữ A của mình để hiển thị như thế nào, gần đúng, tôi sẽ thấy mã được cấu trúc tốt nhất. –

+0

Điều này, http://speculation.org/garrick/kill-9.html, là một bài học hay cho tôi. Tôi nghĩ rằng tôi đã chọn thói quen "-9" khi lần đầu tiên tôi chạm vào một hộp linux. – mathtick

2

Mã này (mã dưới đây) dường như làm việc cho tôi, giết từ "top" hoặc ctrl-c từ dòng lệnh. Sự thay đổi thực sự duy nhất từ ​​đề xuất của Alex là thay thế subprocess.Process với một subprocess.Popen gọi (Tôi không nghĩ rằng subprocess.Process tồn tại).

Mã ở đây cũng có thể được cải thiện bằng cách nào đó khóa stdout để không có cơ hội in chồng chéo giữa các quy trình.

import subprocess, threading, signal 
import sys, time 

pobs = set()       # set to hold the active-process objects 
pobslock = threading.Lock()  # a Lock object to make sure only one at a time can modify pobs 

def numpobs(): 
     with pobslock: 
       return len(pobs) 

# signal handlers 
def sigterm_handler(signal, frame): 
     print 'You killed me! I will take care of the children.' 
     with pobslock: 
       for p in pobs: p.kill() 
     sys.exit(0) 

def sigint_handler(signal, frame): 
     print 'You pressed Ctrl+C! The children will be dealt with automatically.' 
     sys.exit(0) 

signal.signal(signal.SIGINT, sigint_handler) 
signal.signal(signal.SIGTERM, sigterm_handler) 


# a function to watch processes 
def p_watch(d, p): 
     print d, 'start', p.pid 
     rc = p.wait() 
     with pobslock: 
       pobs.remove(p) 
     print d, 'done, rc =', rc 


# the main code 
print "Starting to run things ..." 
for i in range(5): 
     p = subprocess.Popen(['sleep', '4']) 
     with pobslock: 
       pobs.add(p) 
     # create and start a "daemon" to watch and report the process p. 
     t = threading.Thread(target=p_watch, args=(i, p)) 
     t.daemon=True 
     t.start() 

print "Got things running ..." 
while numpobs(): 
     print "Still working ..." 
     time.sleep(1) 
+0

bạn đúng rằng không có subprocess.Process - xin lỗi cho các thinko; -, chỉnh sửa A của tôi bây giờ để sửa chữa nó. –

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