每小時進行 50 萬次數學運算的最有效方法

每小時進行 50 萬次數學運算的最有效方法

因此,出於個人和學習經驗的原因,我開始將天氣資料資料庫化。我正在使用 wgrib2 解析數據,並導入到 MySQL。因為數據採用不同的單位格式 - 風“U”和“V”分量、開爾文等...我必須將其轉換為風速節、風度半徑和溫度攝氏度...等。

我建立了一個 bash for 迴圈來循環遍歷所有資料值,但效率相當低,而且我確信有更好的方法可以做到這一點。它依賴awk,很多...,需要15-17分鐘來解析大約1150個站點的數據,每個站點在MySQL資料庫中有一個結構完全相同的表,有160列。

我為 TK(溫度開爾文)、RH(濕度)等設定的 bash 陣列...具有 1000、975、950、925...等一直到 100 毫巴的值。

for thKey in ${!TK[@]}
do
    thRH=${RH[$thKey]}
    thTK=${TK[$thKey]}
    thTC=$(echo -| awk -v tk="$thTK" '{printf "%.1f\n", tk-273.15}')
    thWU=${WU[$thKey]}
    thWV=${WV[$thKey]}
    thTD=$(echo -| awk -v tc="$thTC" -v rh="$thRH" '{printf "%.1f\n", tc-(100-rh)/5}')
    thWD=$(echo -| awk -v wu="$thWU" -v wv="$thWV" '{printf "%.0f\n", 57.29578*(atan2(wu, wv))+180}')
    thWS=$(echo -| awk -v wu="$thWU" -v wv="$thWV" '{printf "%.1f\n", sqrt(wu*wu+wv*wv)*1.944}')
    sed -i '/\/station_id/a <'"$thKey"'T>'"$thTC"'<\/'"$thKey"'T><'"$thKey"'D>'"$thTD"'<\/'"$thKey"'D><'"$thKey"'WD>'"$thWD"'<\/'"$thKey"'WD><'"$thKey"'WS>'"$thWS"'<\/'"$thKey"'WS>' $xmlOut
done

正如你所看到的,明顯的問題是它對awk 進行了大約1150 * 160 次調用...所以可能將主數組傳遞給awk 並且每個循環只生成awk 一次(我現在正在做的事情的1 /160! )會更有效率。但我似乎無法獲得適合這種做法的 awk 語法...

awk --version

GNU Awk 4.1.3,API:1.1(GNU MPFR 3.1.4,GNU MP 6.1.0)

這是一個例子:

TK=(325,350,231,655)
echo -| awk -v tk="${TK[*]}" '{split(tk,tka,/ /)} { for (i=0; i<=NF; i++) { printf "%.1f\n", tka[i]-273.15 } } '

-273.1 51.9

^ 這是不對的。該陣列有 4 個值,它不應該只傳回 2 個。

echo -| awk -v tk="${TK[*]}" '{split(tk,tka,/ /)} { for (i=0; i<=length(tka); i++) { printf "%.1f\n", tka[i]-273.15 } } '

^ 這會產生無限循環。

有任何想法嗎?也許學習一些 Perl 並將所有這些傳遞給 Perl 腳本?

答案1

就我個人而言,是的,我會用 Perl 來完成這一切。 :-)

TK=(325,350,231,655)

哎呀。小心。您已經建立了一個單元素數組,其中以逗號分隔的字串作為元素。

echo -| awk -v tk="${TK[*]}" '{split(tk,tka,/ /)} { for (i=0; i<=NF; i++) { printf "%.1f\n", tka[i]-273.15 } } '

awk陣列從 1 開始,而不是從零開始。

因為您指派了變量,所以您實際上並沒有將 STDIN 資料用於 NF 值以外的任何內容(但您只傳入了一個元素)。我們不使用 NF,而是明確地計算結果split。也許是這樣的:

$ TK=(325 350 231 655)
$ echo - | awk -v tk="${TK[*]}" '{fields=split(tk,tka,/ /)} { for (i=1; i<=fields; i++) { printf "%.1f\n", tka[i]-273.15 } } '
51.9
76.9
-42.1
381.9

正如 dave_thompson_085 所提到的,您透過直接將資料分配給變數而不是僅透過 STDIN 發送它來完成額外的工作。更常見的可能是這樣的:

$ echo ${TK[*]} | awk '{for (i=1; i<=NF; i++) { printf "%.1f\n", $i-273.15 } } '
51.9
76.9
-42.1
381.9

如果您確實想要開始解決perl方案:

$ echo ${TK[*]} | perl -lane 'for $item (@F) {print $item-273.15}'
51.85
76.85
-42.15
381.85

相關內容