2012-12-15 27 views
5

Khá đơn giản, tôi muốn chạy lệnh/chương trình bên ngoài từ bên trong một tập lệnh Python, sau khi hoàn thành, tôi cũng muốn biết lượng thời gian CPU của nó tiêu thụ.Chạy lệnh bên ngoài và lấy số lượng CPU mà nó tiêu thụ

Chế độ cứng: chạy nhiều lệnh song song sẽ không gây ra sự thiếu chính xác trong kết quả tiêu thụ CPU.

+2

Điều này có phải là đa nền tảng không? Nếu không, hệ điều hành nào được cho là chạy? Hầu hết các hệ điều hành đều cung cấp quyền truy cập vào các bộ tính giờ khác nhau, nhưng các hệ điều hành chính xác nhất có thể yêu cầu đặc quyền nâng cao. –

+0

Chỉ cần Linux là tốt, Windows tương thích được đánh giá cao nhưng không cần thiết. –

Trả lời

10

Trên UNIX: (a) sử dụng resource mô-đun (xem thêm câu trả lời bằng icktoofay), hoặc (b) sử dụng lệnh time và phân tích kết quả, hoặc (c) sử dụng /proc hệ thống tập tin, phân tích/proc/[ pid]/stat và phân tích cú pháp ra các trường utimestime. Điều cuối cùng trong số này là dành riêng cho Linux.

Ví dụ về sử dụng resource:

import subprocess, resource 
usage_start = resource.getrusage(resource.RUSAGE_CHILDREN) 
subprocess.call(["yourcommand"]) 
usage_end = resource.getrusage(resource.RUSAGE_CHILDREN) 
cpu_time = usage_end.ru_utime - usage_start.ru_utime 

Lưu ý: nó không phải là cần thiết để làm ngã ba/execvp, subprocess.call() hay subprocess phương pháp khác cũng tốt ở đây và dễ dàng hơn để sử dụng.

Lưu ý: bạn có thể chạy nhiều lệnh từ cùng một tập lệnh python đồng thời hoặc sử dụng subprocess.Popen hoặc subprocess.call và luồng, nhưng tài nguyên sẽ không trả về đúng thời gian cpu riêng của nó, nó sẽ trả về tổng thời gian của chúng trong giữa các cuộc gọi đến getrusage; để có được thời gian riêng lẻ, hãy chạy một trình bao nhỏ python cho mỗi lệnh theo thời gian như trên (có thể khởi chạy từ kịch bản chính của bạn) hoặc sử dụng phương thức time bên dưới, sẽ hoạt động chính xác với nhiều lệnh đồng thời (thời gian cơ bản là như vậy một wrapper).

Ví dụ về sử dụng time:

import subprocess, StringIO 
time_output = StringIO.StringIO() 
subprocess.call(["time", "yourcommand", "youroptions"], stdout=time_output) 
# parse time_output 

Trên Windows: Bạn cần phải sử dụng bộ đếm hiệu suất (aka "hiệu suất giúp việc dữ liệu") bằng cách nào đó. Đây là một C example của API cơ bản. Để lấy nó từ python, bạn có thể sử dụng một trong hai mô-đun: win32pdh (một phần của pywin32; sample code) hoặc pyrfcon (nền tảng chéo, cũng hoạt động trên Unix; sample code).

Bất kỳ phương pháp nào trong số này thực sự đáp ứng các yêu cầu "chế độ khó" ở trên: chúng phải chính xác ngay cả với nhiều phiên bản đang chạy khác nhau trên một hệ thống bận. Chúng có thể không tạo ra kết quả chính xác trong trường hợp đó so với chỉ chạy một tiến trình trên hệ thống nhàn rỗi, bởi vì quá trình chuyển đổi có một số chi phí, nhưng chúng sẽ rất gần, vì cuối cùng chúng thu thập dữ liệu của chúng từ bộ lập lịch OS.

+0

+1 với nhận xét rằng việc sử dụng '/ proc' theo cách này là đặc trưng cho Linux. –

3

Bạn có thể làm timings trong Python, nhưng nếu bạn muốn biết mức tiêu thụ CPU tổng thể của chương trình của bạn, đó là loại ngớ ngẩn để làm. Điều tốt nhất cần làm là chỉ sử dụng chương trình GNU time. Nó thậm chí còn tiêu chuẩn trong hầu hết các hệ điều hành.

+0

Tôi muốn chạy lệnh này theo chương trình từ bên trong một tập lệnh Python, tôi đã làm cho câu hỏi của mình rõ ràng hơn một chút. Tôi muốn có thể nhận được kết quả của lệnh cũng như lượng thời gian CPU được sử dụng. –

1

Bạn có thể làm điều này bằng ipython của %time magic function:

In [1]: time 2**128 
CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s 
Wall time: 0.00 
Out[1]: 340282366920938463463374607431768211456L 

In [2]: n = 1000000 

In [3]: time sum(range(n)) 
CPU times: user 1.20 s, sys: 0.05 s, total: 1.25 s 
Wall time: 1.37 
Out[3]: 499999500000L 
+1

Sẽ rất thú vị khi biết lý do tại sao điều này bị giảm bớt ... –

4

Trên nền tảng nơi nó có sẵn, the resource module có thể cung cấp những gì bạn cần. Nếu bạn cần thời gian nhiều lệnh cùng một lúc, bạn có thể muốn (cho mỗi lệnh bạn muốn chạy) fork và sau đó tạo ra các subprocess để bạn nhận được thông tin cho chỉ có quá trình đó. Dưới đây là một cách để bạn có thể làm điều này:

def start_running(command): 
    time_read_pipe, time_write_pipe = os.pipe() 
    want_read_pipe, want_write_pipe = os.pipe() 
    runner_pid = os.fork() 
    if runner_pid != 0: 
     os.close(time_write_pipe) 
     os.close(want_read_pipe) 
     def finish_running(): 
      os.write(want_write_pipe, 'x') 
      os.close(want_write_pipe) 
      time = os.read(time_read_pipe, struct.calcsize('f')) 
      os.close(time_read_pipe) 
      time = struct.unpack('f', time)[0] 
      return time 
     return finish_running 
    os.close(time_read_pipe) 
    os.close(want_write_pipe) 
    sub_pid = os.fork() 
    if sub_pid == 0: 
     os.close(time_write_pipe) 
     os.close(want_read_pipe) 
     os.execvp(command[0], command) 
    os.wait() 
    usage = resource.getrusage(resource.RUSAGE_CHILDREN) 
    os.read(want_read_pipe, 1) 
    os.write(time_write_pipe, struct.pack('f', usage.ru_utime)) 
    sys.exit(0) 

Sau đó bạn có thể sử dụng nó để chạy một vài lệnh:

get_ls_time = start_running(['ls']) 
get_work_time = start_running(['python', '-c', 'print (2 ** 512) ** 200']) 

Sau khi mã đã thực hiện, cả trong những lệnh nên chạy song song. Khi bạn muốn chờ đợi cho họ để kết thúc và nhận được thời gian họ đã thực hiện, gọi hàm trả về bởi start_running:

ls_time = get_ls_time() 
work_time = get_work_time() 

Bây giờ ls_time sẽ chứa thời ls mất để thực hiện và work_time sẽ chứa thời python -c "print (2 ** 512) ** 200" mất để thực hiện.

1

Mô-đun timeit của python rất hữu ích cho các mục đích đo điểm chuẩn/lược tả. Thêm vào đó bạn thậm chí có thể gọi nó từ giao diện dòng lệnh. Để đánh giá một lệnh bên ngoài, bạn sẽ thực hiện như sau:

>>> import timeit 
>>> timeit.timeit("call(['ls','-l'])",setup="from subprocess import call",number=1) #number defaults to 1 million 
total 16 
-rw-rw-r-- 1 nilanjan nilanjan 3675 Dec 17 08:23 icon.png 
-rw-rw-r-- 1 nilanjan nilanjan 279 Dec 17 08:24 manifest.json 
-rw-rw-r-- 1 nilanjan nilanjan 476 Dec 17 08:25 popup.html 
-rw-rw-r-- 1 nilanjan nilanjan 1218 Dec 17 08:25 popup.js 
0.02114391326904297 

Dòng cuối cùng là thời gian thực hiện được trả về. Ở đây, đối số đầu tiên là timeit.timeit() là mã để gọi phương thức bên ngoài và đối số setup chỉ định mã chạy trước khi bắt đầu đo thời gian. Đối số number là số lần bạn muốn chạy mã được chỉ định và sau đó bạn có thể chia thời gian được trả về theo số number để nhận thời gian trung bình.

Bạn cũng có thể sử dụng phương pháp timeit.repeat() mà mất lập luận tương tự như timeit.timeit() nhưng phải mất thêm repeat lập luận để xác định số lượng thời gian timeit.timeit() nên được gọi và trả về một danh sách các lần thực hiện cho mỗi lần chạy.

Lưu ý: Thời gian thực hiện trả về theo phương pháp timeit.timeit() là thời gian đồng hồ treo tường, không phải là thời gian của CPU. Vì vậy, các quy trình khác có thể ảnh hưởng đến thời gian. Vì vậy, trong trường hợp của timeit.repeat() bạn nên lấy giá trị tối thiểu thay vì cố gắng tính toán độ lệch trung bình hoặc tiêu chuẩn.

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