gpt4 book ai didi

bash - 为什么我的程序需要这么长时间才能运行?

转载 作者:行者123 更新时间:2023-11-29 09:27:35 25 4
gpt4 key购买 nike

我用 bash 编写了一个小程序,它可以将多行(制表符)六列转换为一行 12 列,如下所示:

    $1          $2      $3          $4          $5  $6      $7      $8      $9  $10     $11     $12
input
Scaffold952 345718 345781 aug3.g8795.t1 . -
Scaffold952 346504 346534 aug3.g8795.t1 . -
Scaffold952 346721 346733 aug3.g8795.t1 . -
Scaffold952 348148 348241 aug3.g8795.t1 . -
output
Scaffold952 345718 345781 aug3.g8795.t1 . - 345718 345718 0 4 63,30,12,93 0,786,1003,2430

要完成这个:

  1. 获取六列输入,按名称排序(第 4 列),然后按开头排序(第 2 列)
  2. 根据输入生成姓名列表并删除重复项
  3. 第 2 步中生成的 foreach 行
    • 在输入中找到对应的行
    • 使用第二和第三列构建第 11 和 12 列,将值插入数组
    • 组合列和数组以形成最终的 12 列输出
  4. 插入输出文件

第 11 列由 $3 - $2 组成;第 12 列由 $2 减去第一个 $2 值 (345718) 组成,每 6 列行并打印为 csv。

我的代码:

#!/bin/bash

input=$1
output=$2
> $output
# functions
function joinArray { local IFS="$1"; shift; echo "$*"; }
# sort input
sort -k4,4 -k2,2 -o $input < $input

awk '{ print $4 }' $input | uniq | while read -r line; do
dup="$(grep -c $line $input)"
start="$(grep $line $input | awk 'NR==1 { print $2 }')"
records="$(grep $line $input | awk 'NR==1 { print $0 }')"

grep $line $input | {
while read -r record; do
blocksize+=($(awk '{ print $3 - $2 }' <<< "$record"))
blockstart+=($(awk -v var="$start" '{ print $2 - var }' <<< "$record"))
done
# combine input with arrays to form 12 col output
bed12[0]+=$(awk '{ print $1 }' <<< "$records")
bed12[1]+=$(awk '{ print $2 }' <<< "$records")
bed12[2]+=$(awk '{ print $3 }' <<< "$records")
bed12[3]+=$(awk '{ print $4 }' <<< "$records")
bed12[4]+=$(awk '{ print $5 }' <<< "$records")
bed12[5]+=$(awk '{ print $6 }' <<< "$records")
bed12[6]+=$(awk '{ print $2 }' <<< "$records")
bed12[7]+=$(awk '{ print $2 }' <<< "$records")
bed12[8]+='0'
bed12[9]+=$dup
bed12[10]+=$(joinArray $',' "${blocksize[@]}")
bed12[11]+=$(joinArray $',' "${blockstart[@]}")

joinArray $'\t' "${bed12[@]}" >> $output
}
done

到目前为止,我一直无法使这段代码高效运行,我正在寻求改进它,因为对于一个标准大小的文件(约 30,000 行),它需要三个小时才能完成。我不确定是什么导致了问题,可能是每次写入记录时打开/关闭输出文件;嵌套的 while 循环;阵列?这是一个糟糕的程序,语言不是合适的选择,还是对于这么大 (1.7 MB) 的文件来说这是预期的?

最佳答案

注意事项:

  • 您放入 while read 中的所有内容每处理一行循环运行一次。
  • 正在运行 $(...)执行 fork() 调用,创建一个全新的进程树条目,在该新进程中运行包含的代码,读取其标准输出,并等待进程完成。这是一个很多的开销。
  • 每次运行 awk -- 虽然它是一个非常快的语言解释器 -- 或 grep ,您实际上是在启动一个新程序:将其 fork ,动态加载其库依赖项,连接其标准输入和标准输出……这也是很多开销。
  • 每次进行重定向时,例如 >>foo ,即打开命令的输出文件,然后在该文件完成后再次关闭它。 (对于 shell 语言尤其如此;一些 awk 实现 > 缓存和重用文件描述符,特别是 GNU 的)。
  • 不幸的是,在撰写本文时,<<< 的 bash 实现涉及在磁盘上创建一个临时文件。如果在 /dev/fd 平台上的紧密内循环中使用此构造是受支持的接口(interface),< <(printf '%s' "$foo")因此可能比 <<<"$foo" 更快-- 尽管我不建议在实践中实际这样做,除非您需要它,因为 bash 的 future 版本有望解决该行为并使用更易于阅读的语法做正确的事情。

那么,你能做什么?

  • 对于 awk 等工具,仅当您可以跨多行输入重复使用单个长时间运行的实例时才使用它们。

    坦率地说,这是这里最重要的推荐。将所有工作从 bash 移到单个 awk调用,你就完成了。

  • 要将输入流解析为多个字段,请使用 bash 自己的内置函数:

    read -r first_field second_field third_field ...
  • 使用 exec >foo 在封闭的外部范围内进行重定向为整个程序(或整个子 shell,如果在这样的上下文中执行)重定向标准输出,或放置 >foodone之后关闭循环以在该循环期间重定向标准输出。

关于bash - 为什么我的程序需要这么长时间才能运行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38384872/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com