跳轉至內容

Shell 程式設計/最佳化

來自華夏公益教科書,開放的書籍,面向開放的世界

最佳化

[編輯 | 編輯原始碼]

如果效能是主要問題,則應使用編譯語言(如 C)或至少是更高效能的解釋語言(如 Python),而不是 shell 指令碼。此外,效能通常受呼叫的外部命令(以及呼叫開銷)和 shell 本身的影響,而不是特定的指令碼或其邏輯。因此,最佳化的主要方法是呼叫更少或更便宜的外部命令,或使用更最佳化的 shell,通常是針對指令碼最佳化的更簡單的 shell,如 ash 或 dash,而不是複雜的 shell,如 bash。

但是,一些更精細的最佳化是可能的,並且可以使用效能分析來識別由單獨命令而不是指令碼本身引起的瓶頸。

效能分析

[編輯 | 編輯原始碼]

最簡單的方法是,以詳細模式執行指令碼(在 bash 中,使用 -x 標誌或在指令碼頂部使用 set -x),並檢視執行明顯掛起的位置 - 這是一種快速識別瓶頸的方法。

接下來,使用 time 來測量指令碼或任何特定命令所使用的時間。這可能是一個 shell 內建命令,如 bash 中的命令,但(外部)GNU time 程式提供了更復雜的分析。您可以按如下方式呼叫它們(最後一個假設了 time 二進位制檔案的路徑)

time ./foo
`which time` -v ./foo
/usr/bin/time -v ./foo

特別有用的資料是

  • 真即時間/使用者時間/系統時間(掛鐘時間、使用者空間 CPU 時間、作業系統 CPU 時間) - 底線
  • 上下文切換 - 衡量切換到外部程式或核心,以及返回
  • 頁面錯誤

這使您可以快速測量更改的影響。

請注意,此測量結果是有噪聲的 - 特別是如果其他任務正在執行 - 並且執行指令碼和 time 命令本身會產生開銷。此外,由於快取為空,效能在第一次執行時通常會更慢。為了處理噪聲和快取,請終止其他任務(或透過 top 檢查系統是否沒有負載)並執行指令碼幾次。為了校準基線開銷,請對真實(外部)命令、真實(內建的,如果可用)以及空指令碼計時,以檢視總體流程和指令碼開銷。

對於執行時間更長的指令碼,在 Linux 上,您可以在 /proc/$pid/status 中檢視一些資訊,您可以透過 watch /proc/$pid/status 來監控。請注意,您可以使用 grep 只選擇某些資料,例如上下文切換(ctxt)。

對於系統呼叫,strace,尤其是 strace -c,會分解系統呼叫的成本。

更詳細地,您可以使用 date 對指令碼的各個部分進行計時,並比較連續的時間戳。例如,使用 GNU date 和納秒精度

date --rfc-3339=ns

這可能足以識別瓶頸,儘管二分搜尋可能很繁瑣。

要分析整個指令碼,最簡單的方法是開啟詳細模式(在 bash 中)並透過 date 管道,這會為每一行生成時間戳;您也可以在 bash 中設定 PS4,每次呼叫 date(主要開銷)或使用內建的日期格式說明符(在 Bash 4.2 或更高版本中)。一些簡單的操作(使用 tee 和 paste)可以生成一個帶有每行所需時間的帶註釋的指令碼。請參閱 F. Hauri 的回答,瞭解如何 分析 bash shell 指令碼? - 請注意(目前)行號會少一個(時間是前一行的成本) - 或者使用 bashProfiler

這種分析對於具有簡單流程的指令碼(一系列命令)已經足夠了,但不能檢測迴圈或遞迴中的熱點。類似於 gperf 的更復雜的效能分析器不適用於 shell 指令碼,但(假設指令碼行是唯一的,如果需要,可以透過新增手動行號來確保)簡單地處理帶時間戳的日誌可以讓你跨行求和,並識別熱點。

內建命令

[編輯 | 編輯原始碼]

最佳化 shell 指令碼的一項關鍵技術是使用內建命令替換對外部命令的呼叫。這消除了大量的程序開銷以及相關的上下文切換和頁面錯誤,這些是導致效能緩慢的主要原因。一個很好的例子是在 bash 中使用字串操作,而不是對 sed 進行外部呼叫。

檢視差異(在 bash 中)的一種簡單方法是對呼叫內建的 true 和外部 true 程式進行效能分析

#!/bin/bash
for i in {1..1000} ; do true ; done
#!/bin/bash
for i in {1..1000} ; do /bin/true ; done

透過以下方式進行效能分析

/usr/bin/time -v ./true-int-1000
/usr/bin/time -v ./true-ext-1000

呼叫外部命令的指令碼會慢很多,這主要是因為有更多的上下文切換(至少多 2000 次,因為切換到 true 然後再返回);以及頁面錯誤 - 實際命令什麼也不做(成功了)。

華夏公益教科書