2009-11-06 16 views
33

Tôi cần giới hạn lượng thời gian và CPU được thực hiện bởi các ứng dụng dòng lệnh bên ngoài mà tôi sinh ra từ quá trình python bằng cách sử dụng subprocess.call, chủ yếu là do đôi khi quá trình sinh ra bị kẹt và ghim CPU ở mức 99%.Python: ulimit và tốt đẹp cho subprocess.call/subprocess.Popen?

tốt và ulimit có vẻ là cách hợp lý để thực hiện việc này, nhưng tôi không chắc chắn cách họ tương tác với quy trình con.

  • Các giới hạn giống như thế:
    • Giết quá trình này nếu nó được dùng hơn 60 giây
    • Giới hạn nó đến 20% cpu
  • Tôi muốn áp dụng các nguồn tài nguyên hạn chế cho tiến trình con, không phải với tiến trình python, nó sinh ra các tiến trình con.

Có cách nào để áp dụng tốt đẹp và ulimit cho quá trình sinh sản subprocess.call? Có lựa chọn thay thế bản địa tốt hơn?

Đây là trên hệ thống linux (ubuntu).

+1

Bạn có thể muốn chấp nhận câu trả lời được bỏ phiếu cao nhất thay vì câu trả lời của tôi. Nó tốt hơn tôi nhiều. –

Trả lời

10

Bạn có thể đặt ra giới hạn cho subprocesses với các lệnh ulimitnice vỏ như thế này:

import subprocess 
subprocess.Popen('ulimit -t 60; nice -n 15 cpuhog', shell=True) 

này chạy cpuhog với một giới hạn là 60 giây thời gian CPU và điều chỉnh giá trị nice của 15. Lưu ý rằng có không có cách đơn giản để thiết lập một ga 20% CPU như vậy. Quá trình này sẽ sử dụng CPU 100% trừ khi một quá trình khác (ít đẹp hơn) cũng cần CPU.

+0

Cảm ơn Ville, việc điều chỉnh CPU bạn mô tả công trình tuyệt vời. Bạn có biết nếu nó có thể làm điều tương tự chỉ định lệnh với cú pháp khung thay vì như một chuỗi? – Parand

+0

Theo như tôi có thể nói, bạn phải vượt qua toàn bộ lệnh shell trong một chuỗi cho một cái gì đó như thế này để làm việc. –

+1

Đây thực sự không phải là giải pháp cần được đánh dấu là câu trả lời được chấp nhận. Kết hợp với các tham số do người dùng cung cấp, điều này có thể dễ dàng kết thúc khi mở lỗ bảo mật. –

86

Sử dụng tham số preexec_fn để subprocess.Popen và mô-đun tài nguyên. Ví dụ:

parent.py:

#!/usr/bin/env python 

import os 
import sys 
import resource 
import subprocess 

def setlimits(): 
    # Set maximum CPU time to 1 second in child process, after fork() but before exec() 
    print "Setting resource limit in child (pid %d)" % os.getpid() 
    resource.setrlimit(resource.RLIMIT_CPU, (1, 1)) 

print "CPU limit of parent (pid %d)" % os.getpid(), resource.getrlimit(resource.RLIMIT_CPU) 
p = subprocess.Popen(["./child.py"], preexec_fn=setlimits) 
print "CPU limit of parent (pid %d) after startup of child" % os.getpid(), resource.getrlimit(resource.RLIMIT_CPU) 
p.wait() 
print "CPU limit of parent (pid %d) after child finished executing" % os.getpid(), resource.getrlimit(resource.RLIMIT_CPU) 

child.py:

#!/usr/bin/env python 

import os 
import sys 
import resource 

print "CPU limit of child (pid %d)" % os.getpid(), resource.getrlimit(resource.RLIMIT_CPU) 

parent.py sẽ phân nhánh thành một quá trình mới. Trong quá trình mới, nó sẽ gọi setlimits(), sau đó thực hiện child.py. Điều này có nghĩa là tài nguyên sẽ bị giới hạn trong tiến trình con, nhưng không bị giới hạn trong phụ huynh.

Output chương trình khi chạy:

./parent.py 
CPU limit of parent (pid 17404) (-1, -1) 
Setting resource limit in child (pid 17405) 
CPU limit of parent (pid 17404) after startup of child (-1, -1) 
CPU limit of child (pid 17405) (1, 1) 
CPU limit of parent (pid 17404) after child finished executing (-1, -1) 

Đây là trong nhiều trường hợp là một giải pháp tốt hơn so với cố gắng sử dụng ulimit, vì nó không phải luôn luôn là một ý tưởng tốt để đẻ trứng subprocess qua vỏ, đặc biệt là kể từ khi nó thường gây tham số xấu xí trích dẫn sự cố.

+0

Cảm ơn Erik. Có vẻ như điều này đặt ra các giới hạn về quá trình python, không phải trên quy trình bên ngoài? – Parand

+0

Quá trình Python và tất cả các con của nó. Từ trang người đàn ông: Giới hạn về việc tiêu thụ tài nguyên hệ thống theo quy trình hiện tại và mỗi quá trình mà nó tạo ra có thể thu được bằng lệnh getrlimit() và được thiết lập với setrlimit() gọi điện. –

+2

Có, gói tài nguyên thiết lập giới hạn về quá trình python (thông qua setrlimit) - nhưng trong ví dụ của tôi, nó đặt giới hạn trên tiến trình con được tạo ra bởi subproces.Popen, trước khi gọi hàm exec() để chạy con. Vì vậy, trong ví dụ, quy trình gọi điện thoại 'giới hạn không bị ảnh hưởng, chỉ giới hạn của trẻ. –

6

Erik làm cho nó dễ dàng đối với tôi, nhưng ông quên nice phần mà Giàu Chỉ ra. Tôi tìm thấy gói psutil tốt đẹp (chơi chữ dự định) nhưng tiếc là ít di động hơn.Đây là quan điểm của tôi với câu hỏi:

import os 
import psutil 
import resource 
import subprocess 

def preexec_fn(): 
    pid = os.getpid() 
    ps = psutil.Process(pid) 
    ps.set_nice(10) 
    resource.setrlimit(resource.RLIMIT_CPU, (1, 1)) 

print "mother pid", os.getpid() 
p = subprocess.Popen(["./cpuhog.sh"], preexec_fn=preexec_fn) 
p.wait() 
print "mother still alive with pid", os.getpid() 

Ville sử dụng shell=True mà tôi bằng cách nào đó dị ứng. Có lẽ tôi chỉ già và gắt gỏng ở đây, nhưng tôi cố gắng tránh nó!

+3

Tại sao bạn cần 'psutil' khi nội trang' os' của Python đã có 'nice'? – WGH

+0

Có lẽ vì bạn không thể chuyển PID tới 'os.nice', nhưng bạn có thể dùng' psutil'. –