每小时进行 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

相关内容