提高 bash 中将文件列与数组进行比较的性能
Improving performance of comparing file column to array in bash
我正在将一系列文件中的行与 bash 中的浮点数组进行比较。简而言之,有问题的文件 (../summarize_eigenvectors/"$xct"_/-5_1-sorted.txt) 具有以下结构
c v weight ik kx ky kz
1 1 0.00000 1 0.00000 0.00000 0.00000
1 1 0.00000 2 0.00000 0.04167 0.00000
1 1 0.00000 3 0.00000 0.08333 0.00000
数组由../vici_absdipole_noeh/v1c5.data生成,格式如下:
kx ky kz ik ic iv is ec (eV) ev (eV) eig (eV) abs(dipole)^2 Re(dipole) Im(dipole)
0.00000 0.00044 0.00000 1 1 1 1 0.11713703E+01 -0.12426462E+01 0.24140165E+01 0.69913425E-04 0.81359347E-02 0.19287282E-02
0.00000 0.01883 0.00000 2 1 1 1 0.11760590E+01 -0.12490846E+01 0.24251436E+01 0.59405512E-04 -0.70114501E-03 0.76755396E-02
0.00000 0.03722 0.00000 3 1 1 1 0.11746489E+01 -0.12612625E+01 0.24359113E+01 0.37648401E-04 -0.46637404E-02 0.39872204E-02
0.00000 0.05561 0.00000 4 1 1 1 0.11868220E+01 -0.12787400E+01 0.24655620E+01 0.18552618E-04 -0.21585915E-02 0.37273450E-02
我的代码所做的是将文件 v1c5.da 第 4 列中的整数与我的数组进行比较;如果对于文件的一行,第 4 列元素在“列表”数组中,则回显该行中的文件索引、权重、ik、kx 和 ky 的值。
这是我的工作代码示例,它将 7485 个文件(每个文件有 1152 行)与 1152 个元素的数组进行比较
#!/bin/bash
#generates the array from information given in another file
for i in range $(seq 2 1153)
do
ik=$(awk -v i=$i 'NR==i''{ print }' ../vici_absdipole_noeh/v1c5.data)
dp2=$(awk -v i=$i 'NR==i''{ print }' ../vici_absdipole_noeh/v1c5.data)
dp2f=$(printf "%.8f" $dp2)
if (( $(echo "$dp2f > 6" |bc -l) )); then
list+=("$ik" )
fi
done
echo "xct ik weight kx ky" > v1c5-high_dp2_kpts.txt
task(){
echo working on $xct
for line in {1..1152};do
weight=$(awk -v line=$line 'NR==line''{ print }' ../summarize_eigenvectors/"$xct"_*/*-5_1-sorted.txt)
ik=$(awk -v line=$line 'NR==line''{ print }' ../summarize_eigenvectors/"$xct"_*/*-5_1-sorted.txt)
kx=$(awk -v line=$line 'NR==line''{ print }' ../summarize_eigenvectors/"$xct"_*/*-5_1-sorted.txt)
ky=$(awk -v line=$line 'NR==line''{ print }' ../summarize_eigenvectors/"$xct"_*/*-5_1-sorted.txt)
if [[ " ${list[@]} " =~ " ${ik} " ]]; then
echo "$xct $ik $weight $kx $ky" >> v1c5-high_dp2_kpts.txt
fi
done
}
for xct in {1..7485};do
((i=i%360)); ((i++==0)) && wait
task "$xct" &
done
wait
代码运行8小时多,只处理了1700个文件,速度相当慢。此代码中是否存在限制其性能的瓶颈?如果有,我该如何改进?
我运行在每个节点有 24 个内核的高性能计算中心节点上执行此操作,因此我也使用并行化来加快速度。显然这还不够。
你的 task
功能真的很低效。它通过循环每次重新读取所有文件 4 次,只处理一行。您可以在一次 awk
调用中完成所有工作。
task(){
echo working on $xct
cat ../summarize_eigenvectors/"$xct"_*/*-5_1-sorted.txt |
awk -v list="${list[*]}" -v xct="$xct" '
BEGIN {
split(list, list_array); # split string list into array list_array at whitespace delimiters
for (i in list_array) list_hash[list_array[i]] = 1 # associative array with $list elements as keys
}
{
weight=; ik=; kx=; ky=;
if (ik in list_hash) printf("%s %s %s %s %s\n", xct, ik, weight, kx, ky)
}' >> v1c5-high_dp2_kpts.txt
}
我正在将一系列文件中的行与 bash 中的浮点数组进行比较。简而言之,有问题的文件 (../summarize_eigenvectors/"$xct"_/-5_1-sorted.txt) 具有以下结构
c v weight ik kx ky kz
1 1 0.00000 1 0.00000 0.00000 0.00000
1 1 0.00000 2 0.00000 0.04167 0.00000
1 1 0.00000 3 0.00000 0.08333 0.00000
数组由../vici_absdipole_noeh/v1c5.data生成,格式如下:
kx ky kz ik ic iv is ec (eV) ev (eV) eig (eV) abs(dipole)^2 Re(dipole) Im(dipole)
0.00000 0.00044 0.00000 1 1 1 1 0.11713703E+01 -0.12426462E+01 0.24140165E+01 0.69913425E-04 0.81359347E-02 0.19287282E-02
0.00000 0.01883 0.00000 2 1 1 1 0.11760590E+01 -0.12490846E+01 0.24251436E+01 0.59405512E-04 -0.70114501E-03 0.76755396E-02
0.00000 0.03722 0.00000 3 1 1 1 0.11746489E+01 -0.12612625E+01 0.24359113E+01 0.37648401E-04 -0.46637404E-02 0.39872204E-02
0.00000 0.05561 0.00000 4 1 1 1 0.11868220E+01 -0.12787400E+01 0.24655620E+01 0.18552618E-04 -0.21585915E-02 0.37273450E-02
我的代码所做的是将文件 v1c5.da 第 4 列中的整数与我的数组进行比较;如果对于文件的一行,第 4 列元素在“列表”数组中,则回显该行中的文件索引、权重、ik、kx 和 ky 的值。
这是我的工作代码示例,它将 7485 个文件(每个文件有 1152 行)与 1152 个元素的数组进行比较
#!/bin/bash
#generates the array from information given in another file
for i in range $(seq 2 1153)
do
ik=$(awk -v i=$i 'NR==i''{ print }' ../vici_absdipole_noeh/v1c5.data)
dp2=$(awk -v i=$i 'NR==i''{ print }' ../vici_absdipole_noeh/v1c5.data)
dp2f=$(printf "%.8f" $dp2)
if (( $(echo "$dp2f > 6" |bc -l) )); then
list+=("$ik" )
fi
done
echo "xct ik weight kx ky" > v1c5-high_dp2_kpts.txt
task(){
echo working on $xct
for line in {1..1152};do
weight=$(awk -v line=$line 'NR==line''{ print }' ../summarize_eigenvectors/"$xct"_*/*-5_1-sorted.txt)
ik=$(awk -v line=$line 'NR==line''{ print }' ../summarize_eigenvectors/"$xct"_*/*-5_1-sorted.txt)
kx=$(awk -v line=$line 'NR==line''{ print }' ../summarize_eigenvectors/"$xct"_*/*-5_1-sorted.txt)
ky=$(awk -v line=$line 'NR==line''{ print }' ../summarize_eigenvectors/"$xct"_*/*-5_1-sorted.txt)
if [[ " ${list[@]} " =~ " ${ik} " ]]; then
echo "$xct $ik $weight $kx $ky" >> v1c5-high_dp2_kpts.txt
fi
done
}
for xct in {1..7485};do
((i=i%360)); ((i++==0)) && wait
task "$xct" &
done
wait
代码运行8小时多,只处理了1700个文件,速度相当慢。此代码中是否存在限制其性能的瓶颈?如果有,我该如何改进?
我运行在每个节点有 24 个内核的高性能计算中心节点上执行此操作,因此我也使用并行化来加快速度。显然这还不够。
你的 task
功能真的很低效。它通过循环每次重新读取所有文件 4 次,只处理一行。您可以在一次 awk
调用中完成所有工作。
task(){
echo working on $xct
cat ../summarize_eigenvectors/"$xct"_*/*-5_1-sorted.txt |
awk -v list="${list[*]}" -v xct="$xct" '
BEGIN {
split(list, list_array); # split string list into array list_array at whitespace delimiters
for (i in list_array) list_hash[list_array[i]] = 1 # associative array with $list elements as keys
}
{
weight=; ik=; kx=; ky=;
if (ik in list_hash) printf("%s %s %s %s %s\n", xct, ik, weight, kx, ky)
}' >> v1c5-high_dp2_kpts.txt
}