Shell-Script

一個 GNU 並行作業隊列腳本

  • June 23, 2022

我在 GitHub 上找到了一個腳本,我對它進行了一些修改,以適應我試圖在隊列中執行的程序的需要。

但是它不起作用,我不確定為什麼。它實際上從未將作業回顯到隊列文件。

這是 GitHub 頁面的連結:

https://gist.github.com/tubaterry/c6ef393a39cfbc82e13b8716c60f7824

這是我修改的版本:

#!/bin/sh

END="END"
true > queue

tail -n+0 -f queue | parallel -j 16 -E "$END"

while read i; do
   echo "command [args] > ${i%.inp}.log 2> ${i%.inp}.err" > queue
done < "jobs.txt"

echo "$END" >> queue
echo "Waiting for jobs to complete"

while [ "$(pgrep 'perl /usr/local/bin/parallel' | grep -evc 'grep' | tr -d " ")" -gt "0" ]; do
   sleep 1
done

touch killtail
mv killtail queue
rm queue

我唯一能想到的是,其中一個步驟在 OpenBSD 上沒有按預期執行。但我重新安排了一個步驟,一切都執行沒有錯誤,但它只送出一個作業。更改tail -n+0 -f queue | parallel -j 16 -E "$END"在第一個 while 循環之後移動並更改true > queue為,touch queue因為我不太確定是什麼true > queue意思。

任何幫助,將不勝感激。

編輯:

我有一個 jobs.txt 文件,其中填充了輸入文件到我計劃執行的命令的路徑。jobs.txt 中的文件將是命令的參數之一,然後我將計算結果輸出到日誌文件,並將任何錯誤輸出到錯誤文件。

我的期望是每個作業將被添加到隊列中,並且並行將執行多達 16 個作業,每個核心一個作為命令的參數之一是每個計算使用一個核心。這將一直持續到它到達由 -E 參數表示的“END”以並行。

正如所寫,從jobs.txt 到隊列沒有任何迴聲。我會再試一次>>

我對原始腳本中的很多事情提出了質疑。我改變了我確定的東西,但我對某些功能感到非常困惑,並決定保持原樣。

我不清楚的其中一件事是 tail -n+0

我不知道那在做什麼

編輯2:

$ {PROGRAM} $ {工作}.inp $ {NCPU} > $ {JOB}.log 2> ${JOB}.err

$ {JOB} is a reference to anywhere between 1 and ∞ calculations depending on how many I need to do at a given time. Currently, jobs.txt has 374 individual tests that I need to run. $ {PROGRAM} 是獲取參數的軟體 $ {JOB}.inp and calculates accordingly. $ {NCPU} 是我希望每個作業使用多少個核心;目前我正在嘗試在 16 核處理器上串列執行每個作業。

目標是在不輸入完整命令的情況下將盡可能多的計算排隊。我只想生成一個列表find calculations -name '*.inp' -print > jobs.txt,然後執行一個腳本,如 SerialRun.sh 或 ParallelRun.sh 並讓它產生結果。根據不同的使用者選擇如何組織他們的工作,作業可能嵌套在許多不同的目錄中,這種使用 find 的方法使我能夠非常快速地送出作業並將結果生成到正確的路徑。隨著每次計算完成,我可以在系統繼續執行測試的同時分析數據。

腳本很可能過於復雜。我正在尋找一個作業隊列系統,並找到了成為 GNU Parallel 項目的 nqs。我找不到很多並行隊列作業的範例,但在 GitHub 上遇到了該腳本並決定試一試。我對它的編寫方式有很多問題,但我對並行性的理解不足以質疑它。

我認為為它建立一個隊列應該比這更簡單一些。

編輯3:

也許正確的方法是這樣做:

while read i; do
   command "$i" > "${i%.inp}".log 2> "${i%.inp}".err | parallel -j 16
done < "jobs.txt"

那行得通嗎?

您不需要這個複雜parallel的腳本,可以自己做任何事情。只需使用或您選擇的任何其他工具.inp從文件列表中刪除副檔名,然後將基本名稱輸入如下:sed``parallel

sed 's/\.inp//' jobs.txt | parallel -j 16 "${PROGRAM} {}.inp > {}.log 2> {}.err"

這假設您的文件名沒有空格或換行符,如果有,您需要在帶引號的命令中引用它們:

sed 's/\.inp//' jobs.txt | parallel -j 16 "${PROGRAM} '{}.inp' > '{}.log' 2> '{}.err'"

{}符號是並行基本功能的一部分,描述man parallel如下:

{} 輸入行。

此替換字元串將替換為從輸入源讀取的完整行。輸入源通常是標準輸入(標準輸入),但也可以用--arg-file:::或給出::::

所以它只是被你傳遞給並行的任何東西所取代,在這種情況下,文件名列表及其副檔名被sed.

或者,您可以使用{.}which is:

{.} 不帶副檔名的輸入行。

此替換字元串將被刪除副檔名的輸入替換。如果輸入行包含 . 在最後一個 / 之後,最後一個 。直到字元串的末尾將被刪除並且 {.} 將被剩餘的替換。例如 foo.jpg 變成 foo,subdir/foo.jpg 變成 subdir/foo,sub.dir/foo.jpg 變成 sub.dir/foo,sub.dir/bar 仍然是 sub.dir/bar。如果輸入行不包含 . 它將保持不變。

替換字元串 {.} 可以使用 –extensionreplace 更改

有了這個,你甚至不需要jobs.txt文件。如果您的所有文件都在同一個目錄中,您可以執行以下操作:

parallel -j 16 "${PROGRAM} {.}.inp > {.}.log 2> {.}.err" ::: *.inp

或者,要使其遞歸地進入子目錄,假設您正在使用bash,您可以執行以下操作:

shopt -s globstar
parallel -j 16 "${PROGRAM} {.}.inp > {.}.log 2> {.}.err" ::: **/*.inp

引用自:https://unix.stackexchange.com/questions/707240