2010-03-30 37 views
20

Khi sử dụng python-daemon, tôi là tạo subprocesses likeso:Python-daemon không giết chết những đứa trẻ của mình

import multiprocessing 

class Worker(multiprocessing.Process): 
    def __init__(self, queue): 
     self.queue = queue # we wait for things from this in Worker.run() 

    ... 

q = multiprocessing.Queue() 

with daemon.DaemonContext(): 
    for i in xrange(3): 
     Worker(q) 

    while True: # let the Workers do their thing 
     q.put(_something_we_wait_for()) 

Khi tôi giết phụ huynh quá trình ma quỉ (tức là không phải là một người lao động) với một tổ hợp phím Ctrl-C hoặc SIGTERM , vv, các em không chết. Làm thế nào để giết bọn trẻ?

Suy nghĩ đầu tiên của tôi là sử dụng atexit để giết tất cả những người lao động, likeso:

with daemon.DaemonContext(): 
    workers = list() 
    for i in xrange(3): 
     workers.append(Worker(q)) 

    @atexit.register 
    def kill_the_children(): 
     for w in workers: 
      w.terminate() 

    while True: # let the Workers do their thing 
     q.put(_something_we_wait_for()) 

Tuy nhiên, những đứa trẻ của daemon là điều khó khăn để xử lý, và tôi muốn có nghĩa vụ cho những suy nghĩ và đầu vào như thế nào điều này nên được thực hiện.

Cảm ơn bạn.

+11

Giết trẻ em của bạn có vẻ giống như một điều "daemonic" để làm ... – ewall

+0

Chắc chắn. Daemon này là * không * lên đến spec. –

+14

Đây có phải là Python không?Bạn không thể chỉ làm 'từ infanticide' ác nhập khẩu hoặc một cái gì đó? – Syntactic

Trả lời

31

Tùy chọn của bạn hơi bị giới hạn. Nếu làm self.daemon = True trong hàm khởi tạo cho lớp Worker không giải quyết được vấn đề của bạn và cố gắng bắt tín hiệu trong Phụ huynh (ví dụ: SIGTERM, SIGINT) không hoạt động, bạn có thể phải thử giải pháp ngược lại - thay vì cha mẹ giết trẻ em , bạn có thể để các em tự tử khi cha mẹ qua đời.

Bước đầu tiên là cung cấp cho hàm tạo Worker số PID của quy trình gốc (bạn có thể thực hiện việc này với os.getpid()). Sau đó, thay vì chỉ làm self.queue.get() trong vòng lặp lao động, làm một cái gì đó như thế này:

waiting = True 
while waiting: 
    # see if Parent is at home 
    if os.getppid() != self.parentPID: 
     # woe is me! My Parent has died! 
     sys.exit() # or whatever you want to do to quit the Worker process 
    try: 
     # I picked the timeout randomly; use what works 
     data = self.queue.get(block=False, timeout=0.1) 
     waiting = False 
    except queue.Queue.Empty: 
     continue # try again 
# now do stuff with data 

Các giải pháp trên sẽ kiểm tra xem nếu phụ huynh PID là khác với những gì nó ban đầu là (có nghĩa là, nếu quá trình con là được thông qua bởi init hoặc lauchd vì cha mẹ qua đời) - xem reference. Tuy nhiên, nếu điều đó không làm việc cho một số lý do bạn có thể thay thế nó với chức năng sau (chuyển thể từ here):

def parentIsAlive(self): 
    try: 
     # try to call Parent 
     os.kill(self.parentPID, 0) 
    except OSError: 
     # *beeep* oh no! The phone's disconnected! 
     return False 
    else: 
     # *ring* Hi mom! 
     return True 

Bây giờ, khi các phụ huynh chết (vì lý do gì), các công nhân trẻ sẽ tự rơi xuống như ruồi - đúng như bạn muốn, bạn daemon! :-D

+1

Giải pháp thông minh & giải thích tuyệt vời! –

+2

Tôi thực sự muốn cung cấp cho bạn nhiều hơn 1 điểm cho câu trả lời này: D – edomaur

+0

không phải là bận rộn này chờ đợi kể từ khi queue.get không chặn nữa? IMO nó sẽ là tốt hơn để chèn một đối tượng đặc biệt (như None) trong hàng đợi với atexit trong chủ đề chính và để cho trẻ em sys.exit() nếu chúng nhận được đối tượng None. – Cedric

2

Atexit sẽ không thực hiện thủ thuật - nó chỉ chạy khi kết thúc không có tín hiệu thành công - xem ghi chú gần đầu docs. Bạn cần thiết lập xử lý tín hiệu thông qua một trong hai phương tiện.

Các tùy chọn dễ dàng hơn-nghe: đặt cờ daemon trên quá trình lao động của mình, mỗi http://docs.python.org/library/multiprocessing.html#process-and-exceptions

Hơi khó nghe có vẻ tùy chọn: PEP-3143 dường như ngụ ý có một cách tích hợp để treo nhu cầu chương trình dọn dẹp trong python- daemon.

+0

Cảm ơn Arthur. Ngẫu nhiên, một câu hỏi liên quan tôi đã đăng là http://stackoverflow.com/questions/2546276/python-process-wont-call-atexit - nó bao gồm một số chủ đề này. Tôi muốn biết các mô hình để đảm bảo rằng trẻ em bị giết (hoặc không trở thành zombie) - Tôi đoán cờ daemon đa xử lý sẽ tạo ra sự khác biệt - nó có bao gồm tất cả các trường hợp không? Những trường hợp gì? –

3

có thể bạn không chỉ cần lưu trữ các pid mẹ khi đứa trẻ đầu tiên được tạo ra (giả sử trong self.myppid) và khi self.myppid là khác nhau từ getppid() có nghĩa là cha mẹ qua đời.

bạn cũng có thể sử dụng tín hiệu để tránh phải kiểm tra xem liệu cha mẹ có thay đổi hay không. Tôi không biết các chi tiết cụ thể nhưng một cái gì đó giống như những gì được mô tả here (at the bottom of the page) có thể hoạt động.

+1

Hmm, thực tế * có thể * hoạt động - 'os.getppid()' sẽ trả về 1 nếu cha mẹ chết (tức là, 'init' (cho Linux) hoặc' launchd' (dành cho Mac OS X) thông qua con). –

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