1時間あたり500,000の数学演算を実行する最も効率的な方法

1時間あたり500,000の数学演算を実行する最も効率的な方法

そこで、個人的、学習的経験上の理由で天気データのデータベース化を始めました。私はwgrib2を使用してデータを解析し、それをMySQLにインポートします。データは風「U」と「V」のコンポーネント、ケルビンなどのさまざまな単位形式を持っているため、風速(ノート)、風度半径、温度(摂氏)などに変換する必要があります。

すべてのデータ値を繰り返すためにbash forループを作成しましたが、これは非常に非効率的であり、これを行うより良い方法があると確信しています。これはawkに大きく依存し、約1150ステーションのデータを解析するのに15〜17分かかります。各ステーションには、160列のMySQLデータベースに同じように構造化されたテーブルがあります。

TK(ケルビン温度)、RH(湿度)などに設定したbash配列の値は、1000、975、950、925...など最大100mbarです。

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に渡し、ループごとに1回だけ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から始まります。

変数を割り当てたため、実際にはNF値以外にSTDINデータを使用しませんでした(ただし、1つの要素のみを渡しました)。 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

おすすめ記事