Shell 腳本的平行處理技術 文章首圖

Shell 腳本的平行處理技術

Shell 腳本的平行處理技術

在日常的 Linux 系統管理或資料處理工作中,我們經常需要執行大量重複性的任務,例如批量轉換檔案格式、掃描多台伺服器狀態,或是下載大量檔案。若採用傳統的「串行」(Sequential)方式,腳本會一個接一個地執行,導致總耗時等於所有任務耗時的總和,這在處理大量資料時顯得效率低下。

透過引入「平行處理」(Parallel Processing)技術,我們可以讓多個任務同時執行,大幅縮短總執行時間。在 Shell 腳本中,實現平行處理主要有兩種常見方式:利用 xargs 的平行選項,以及使用背景工作與 wait 指令。本文将詳細介紹這兩種實用的技巧。

方法一:使用 xargs 進行平行處理

xargs 是 Linux 中強大的工具,配合 -P 參數可以指定同時執行的最大進程數。這是最簡單且無需撰寫複雜邏輯的方式。

假設我們有一個檔案列表 files.txt,內容如下:

file1.txt
file2.txt
file3.txt
file4.txt

我們希望對每個檔案執行一個耗時的命令(例如模擬處理時間)。建立腳本 parallel_xargs.sh

#!/bin/bash

# 建立測試檔案
for i in 1 2 3 4; do
    echo "Content $i" > "file${i}.txt"
done

# 使用 xargs 平行處理,-P 4 表示最多同時執行 4 個進程
# -I {} 表示將輸入的每一行替換 {} 的位置
cat files.txt | xargs -I {} -P 4 -n 1 bash -c 'echo "Processing {} at $(date +%H:%M:%S)"; sleep 2; echo "Finished {} at $(date +%H:%M:%S)"'

執行 bash parallel_xargs.sh,你會發現多個任務幾乎同時開始並結束,總時間約為 2 秒,而非串行的 8 秒。注意 -n 1 確保每次只傳遞一個參數,避免參數合併錯誤。

方法二:使用背景工作與 wait

對於需要更精細控制邏輯(如錯誤處理、動態產生任務)的場景,使用背景工作 &wait 指令更為靈活。

以下是一個動態產生任務並平行執行的範例 parallel_bg.sh

#!/bin/bash

# 定義任務函數
process_task() {
    local id=$1
    echo "Task $id started at $(date +%H:%M:%S)"
    sleep 3  # 模擬耗時操作
    echo "Task $id finished at $(date +%H:%M:%S)"
}

# 最大平行數
MAX_JOBS=4
job_count=0

echo "Starting parallel tasks..."

# 產生 10 個任務
for i in {1..10}; do
    # 啟動背景工作
    process_task $i &
    job_count=$((job_count + 1))

    # 當背景工作數達到上限時,等待其中一個完成
    if [ $job_count -ge $MAX_JOBS ]; then
        wait -n  # 等待任意一個背景工作結束
        job_count=$((job_count - 1))
    fi
done

# 等待所有剩餘的背景工作完成
wait

echo "All tasks completed."

此腳本使用 wait -n(Bash 4.3+ 支援)來等待任一背景工作結束,從而釋放槽位給新任務。這確保了系統不會同時開啟過多進程,避免資源耗盡。

常見問題

1. 平行處理導致輸出混亂

當多個進程同時寫入終端時,輸出內容可能會交錯,難以閱讀。解決方法是將輸出重定向至獨立檔案,或在腳本中使用鎖定機制。例如:

# 將每個任務的輸出寫入專屬檔案
process_task $i 2>&1 | tee "output_${i}.log" &

2. 資源耗盡風險

過多的平行進程可能導致 CPU 或記憶體負載過高。建議根據系統核心數設定最大平行數,例如使用 nproc 取得核心數,並設定為核心數的 1-2 倍:

MAX_JOBS=$(nproc)

小結

Shell 腳本的平行處理能顯著提升自動化任務的效率。對於簡單的批次處理,xargs -P 是最快捷的選擇;而對於需要複雜邏輯控制的場景,背景工作搭配 wait 則提供了更大的彈性。實際應用時,請務必監控系統資源,並妥善處理輸出衝突,以確保腳本的穩定性與可維護性。