2012-12-15 39 views
5

非常簡單,我想從一個Python腳本內運行一個外部命令/程序,一旦完成,我也想知道它有多少CPU時間消耗。運行一個外部命令,並獲得它消耗的CPU數量

硬模式:並行運行多個命令不會導致CPU消耗結果不準確。

+2

這是否必須是多平臺?如果不是,應該運行哪個操作系統?大多數操作系統都提供對不同定時器的訪問,但最準確的可能需要提升權限。 –

+0

只要Linux是好的,Windows兼容性是讚賞,但不必要的。 –

回答

10

在UNIX上:或者(a)使用resource模塊(也見由icktoofay回答),或(b)使用time命令,並解析結果,或(c)使用/proc文件系統,解析的/ proc/[ pid]/stat並解析出utimestime字段。最後一個是Linux專用的。

使用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 

注:這是沒有必要做叉/ execvp,subprocess.call()或其他subprocess方法在這裏罰款和更容易使用。

注意:您可以使用subprocess.Popen或subprocess.call和線程同時運行來自同一python腳本的多個命令,但資源不會返回它們正確的單個cpu時間,它將返回它們在在調用getrusage之間;爲了獲得單獨的時間,每個命令運行一個小python wrapper按照上面的時間計算(可以從主腳本啓動它們),或者使用以下方法:與多個同時執行的命令一起正常工作(時間基本上就是這樣一個包裝)。

使用time的例子:

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

在Windows上:你需要以某種方式使用性能計數器(又名 「性能數據助手」)。這是基礎API的C example。爲了從python中獲得它,你可以使用兩個模塊中的一個:win32pdh(pywin32的一部分; sample code)或pyrfcon(跨平臺,也適用於Unix; sample code)。

任何這些方法實際上都符合上面的「硬模式」要求:即使在繁忙系統上有多個不同進程的運行實例,它們也應該是精確的。與在空閒系統上只運行一個進程相比,它們可能不會產生完全相同的結果,因爲進程切換確實有一些開銷,但它們會非常接近,因爲它們最終從OS調度程序獲取它們的數據。

+0

+1與這種說法使用'/ proc'這種方式是特定於Linux。 –

3

您可以在Python中進行時間安排,但是如果您想知道程序的整體CPU消耗量,那實在太傻了。最好的辦法是隻使用GNU time程序。它甚至在大多數操作系統中都是標準的。

+0

我想從Python腳本中以編程方式運行此命令,我讓我的問題更清晰一些。我希望能夠得到命令的結果以及它使用的CPU時間量。 –

1

你可以做到這一點使用IPython中的%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

很高興知道爲什麼這是downvoted ... –

4

在平臺在何處使用,the resource module可以提供你所需要的。如果您需要同時處理多個命令,則可能需要(對於要運行的每個命令)fork,然後創建子流程,以便僅爲該流程獲取信息。以下是你可以做這樣一個方法:

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) 

然後,您可以使用它來運行一些命令:該代碼已執行

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

後,這兩個命令應該並行運行。當你想等待他們完成,並得到他們把執行時間,調用由start_running返回的功能:

ls_time = get_ls_time() 
work_time = get_work_time() 

現在ls_time將包含時間ls了執行和work_time將包含時間python -c "print (2 ** 512) ** 200"了執行。

1

python的timeit模塊對於基準測試/分析目的非常有用。除此之外,你甚至可以從命令行界面調用它。要對外部命令進行基準測試,您應該這樣做:

>>> 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 

最後一行是返回的執行時間。這裏,timeit.timeit()的第一個參數是調用外部方法的代碼,setup參數指定在時間測量開始之前運行的代碼。 number參數是您希望運行指定代碼的時間數量,然後您可以將number返回的時間除以得到平均時間。

您還可以使用timeit.repeat()方法,採用類似的參數作爲timeit.timeit()但需要額外的repeat參數指定應該叫做時間timeit.timeit()數量和返回的執行時間列表每次運行。

注意timeit.timeit()方法返回的執行時間是掛鐘時間,而不是CPU時間。所以,其他進程可能會影響計時。因此,在timeit.repeat()的情況下,您應該取最小值而不是嘗試計算平均值或標準偏差。