A maneira mais eficiente de fazer meio milhão de operações matemáticas por hora [fechado]

0

Portanto, por motivos de experiência pessoal e de aprendizado, iniciei o banco de dados sobre dados meteorológicos. Eu estou usando o wgrib2 para analisar os dados e importar para o MySQL. Como os dados são formatados em unidades diferentes - vento "U" e "V" componentes, kelvin, etc ... Eu tenho que convertê-lo em velocidade do vento nós, raios de vento raio e graus de temperatura C ... etc.

Eu construí um bash for loop que percorre todos os valores de dados, mas é bastante ineficiente e tenho certeza de que há maneiras melhores de fazer isso. Ele depende do awk, muito ... e leva de 15 a 17 minutos para analisar dados de cerca de 1150 estações, cada estação tem uma estrutura idêntica a todas as 160 colunas no banco de dados MySQL.

As matrizes bash que configurei para TK (temp kelvin), RH (umidade), etc ... possuem valores para 1000, 975, 950, 925 ... etc até 100 milibars.

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

Como você pode ver, o problema óbvio é que ele faz cerca de 1150 * 160 chamadas para o awk ... então provavelmente passando os arrays mestres para o awk e só gerando o awk uma vez por loop (1/16 do que estou fazendo agora!) seria mais eficiente. Mas eu não consigo acertar a sintaxe do awk para essa prática ...

awk --version

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

Veja um exemplo:

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

^ isso não está certo. A matriz tem 4 valores, não deve retornar apenas 2.

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

^ isso gera um loop infinito.

Alguma ideia? Talvez aprender algum perl e passar tudo isso para um script perl?

    
por user3260912 14.10.2016 / 03:29

1 resposta

2

Pessoalmente, sim, eu faria tudo em perl. : -)

TK=(325,350,231,655)

Opa. cuidado. Você criou um único array de elementos com uma string separada por vírgula como o elemento.

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

awk matrizes começam em 1, não em zero.

Como você atribui a variável, você não está realmente usando os dados STDIN para algo diferente do valor NF (mas você passou em apenas um único elemento). Em vez de usar NF, vamos apenas contar o resultado de split explicitamente. Talvez algo assim:

$ 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

Como menciona dave_thompson_085, você está fazendo um trabalho extra atribuindo os dados a uma variável diretamente, em vez de apenas enviá-la via STDIN. Mais comum provavelmente seria algo como:

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

E se você quisesse começar com uma perl solution:

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

Tags