簡體   English   中英

並行運行 shell 腳本

[英]Running shell script in parallel

我有一個 shell 腳本

  1. 隨機播放一個大文本文件(600 萬行和 6 列)
  2. 根據第一列對文件進行排序
  3. 輸出 1000 個文件

所以偽代碼看起來像這樣

file1.sh 

#!/bin/bash
for i in $(seq 1 1000)
do

  Generating random numbers here , sorting  and outputting to file$i.txt  

done

有沒有辦法parallel運行這個shell腳本來充分利用多核CPU?

在這一刻, 。 /file1.sh按順序執行 1 到 1000 次運行,速度非常慢。

謝謝你的幫助。

另一種非常方便的方法是使用gnu parallel ,如果您還沒有它,那么非常值得安裝; 如果任務不一定需要相同的時間,這是非常寶貴的。

seq 1000 | parallel -j 8 --workdir $PWD ./myrun {}

將啟動./myrun 1./myrun 2等,確保一次運行 8 個作業。 如果您想同時在多個節點上運行,它也可以獲取節點列表,例如在 PBS 作業中; 我們向用戶提供的有關如何在我們的系統上執行操作的說明位於此處

更新添加:您想確保您使用的是 gnu-parallel,而不是 moreutils 包中同名的更有限的實用程序(此處描述了兩者的不同歷史。)

查看bash subshel​​ls ,它們可用於並行運行腳本的一部分。

我還沒有測試過這個,但這可能是一個開始:

#!/bin/bash
for i in $(seq 1 1000)
do
   ( Generating random numbers here , sorting  and outputting to file$i.txt ) &
   if (( $i % 10 == 0 )); then wait; fi # Limit to 10 concurrent subshells.
done
wait

要使事情並行運行,您可以在 shell 命令的末尾使用“&”在后台運行它,然后wait默認情況下(即不帶參數)等到所有后台進程完成。 所以,也許並行開始 10 次,然后等待,然后再做 10 次。 您可以使用兩個嵌套循環輕松完成此操作。

在 GNU parallel 的文檔中,有一整套程序可以從 shell 並行運行作業,其中甚至包括它們之間的比較。 有很多很多解決方案。 另一個好消息是,它們在調度作業方面可能非常有效,因此所有內核/處理器始終保持忙碌狀態。

有一個簡單、可移植的程序可以為您完成此任務: PPSS PPSS 會自動為您安排作業,方法是檢查有多少可用內核,並在每次完成另一個作業時啟動另一個作業。

IDLE_CPU=1
NCPU=$(nproc)

int_childs() {
    trap - INT
    while IFS=$'\n' read -r pid; do
        kill -s SIGINT -$pid
    done < <(jobs -p -r)
    kill -s SIGINT -$$
}

# cmds is array that hold commands
# the complex thing is display which will handle all cmd output
# and serialized it correctly

trap int_childs INT
{
    exec 2>&1
    set -m

    if [ $NCPU -gt $IDLE_CPU ]; then
        for cmd in "${cmds[@]}"; do
            $cmd &
            while [ $(jobs -pr |wc -l) -ge $((NCPU - IDLE_CPU)) ]; do
                wait -n
            done
        done
        wait

    else
        for cmd in "${cmds[@]}"; do
            $cmd
        done
    fi
} | display

你可能想看看runp runp是一個簡單的命令行工具,可以並行運行(shell)命令。 當您想一次運行多個命令以節省時間時,它很有用。 它很容易安裝,因為它是一個二進制文件。 它已經在 Linux(amd64 和 arm)和 MacOS/darwin(amd64)上進行了測試。

雖然之前的答案確實有效,但 IMO 可能很難記住它們(當然 GNU parallel除外)。

我有點偏愛與上述類似的方法(( $i % 10 == 0 )) && wait 我也看到這個寫成((i=i%N)); ((i++==0)) && wait ((i=i%N)); ((i++==0)) && wait

其中: N定義為要並行運行的作業數, i是當前作業。

雖然上述方法有效,但它的收益遞減,因為您必須等待所有進程退出才能讓一組新進程開始工作,這會浪費 CPU 時間用於任何具有任何執行時間的任務(也稱為每個任務)。 換句話說,在使用前面描述的方法開始新任務之前,並行任務的數量必須達到 0。

對我來說,當執行一個執行時間不一致的任務時,這個問題變得很明顯(例如,執行從數據庫中清除用戶信息的請求——被請求者可能存在也可能不存在,如果它們存在,可能會有數量級的差異用於與不同請求者關聯的記錄)。 我注意到一些請求會立即得到滿足,而另一些請求會排隊等待一個運行時間稍長的任務成功。 這轉化為一項需要數小時/數天才能完成的任務,而之前定義的方法僅需數十分鍾。

我認為下面的方法是一個更好的解決方案,可以在沒有 GNU parallel的系統(例如 vanilla macOS)上保持持續的任務加載,並且希望比上面的字母湯更容易記住:

WORKER_LIMIT=6 # or whatever - remember to not bog down your system

while read -r LINE; do # this could be any kind of loop
    # there's probably a more elegant approach to getting the number of background processes.
    BACKGROUND_PROCESSES="$(jobs -r | wc -l | grep -Eow '[0-9]+')"

    if [[ $BACKGROUND_PROCESSES -eq $WORKER_LIMIT ]]; then
        # wait for 1 job to finish before starting a new one
        wait -n 
    fi

    # run something in a background shell
    python example.py -item "$LINE" &
done < something.list

# wait for all background jobs to finish
wait

生成隨機數很容易。 假設您有一個像商店數據庫這樣的大文件,並且您想在某些特定的基礎上重寫該文件。 我的想法是計算內核數,將文件拆分為多少個內核,制作一個 script.cfg 文件,split.sh 和 recombine.sh split.sh 將在多少個內核中拆分文件,克隆 script.cfg(更改內容的腳本)在那個巨大的文件中),在多少個內核中克隆 script.cgf,使它們可執行,在克隆中搜索和替換一些變量,這些變量必須知道要處理文件的哪一部分,並在克隆完成后在后台運行它們生成克隆$core.ok 文件,因此當所有克隆完成后,將告訴循環僅在生成所有 .ok 文件時將部分結果重組為單個結果。 它可以用“等待”來完成,但我喜歡我的方式

http://www.linux-romania.com/product.php?id_product=76看底部,部分翻譯成英文,這樣我可以在 2 分鍾內處理 20000 篇 16 列的文章(四核)而不是 8 (單核)您必須關心 CPU 溫度,因為所有內核都以 100% 運行

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM