【问题标题】:Bash: how to optimize/parallelize a search through two large files to replace strings?Bash:如何通过两个大文件优化/并行化搜索以替换字符串?
【发布时间】:2014-11-28 04:38:10
【问题描述】:

我正在尝试找出一种方法来加快模式搜索并在两个大文本文件 (>10Mb) 之间进行替换。 File1 有两列,每行都有唯一的名称。 File2 有一列包含 File1 中的一个共享名称,没有特定的顺序,下面的一些文本跨越可变数量的行。它们看起来像这样:

File1:

uniquename1 sharedname1
uqniename2 sharedname2
...

File2:

>sharedname45
dklajfwiffwf
flkewjfjfw
>sharedname196
lkdsjafwijwg
eflkwejfwfwf
weklfjwlflwf

我的目标是使用 File1 将 sharedname 变量替换为它们对应的唯一名称,如下:

New File2:

>uniquename45
dklajfwif
flkewjfj
>uniquename196
lkdsjafwij
eflkwejf

这是我迄今为止尝试过的:

while read -r uniquenames sharednames; do
    sed -i "s/$sharednames/$uniquenames/g" $File2
done < $File1

它可以工作,但速度非常慢,需要在那些大文件中跋涉。 CPU 使用率是限速步骤,所以我试图并行修改以使用我可以使用的 8 个内核,但无法让它工作。我还尝试将 File1 和 File2 拆分为更小的块并同时分批运行,但我也无法让它工作。您将如何并行实现这一点?还是您看到了不同的做法?

欢迎提出任何建议。

更新 1

太棒了!感谢@Cyrus 和@JJoao 以及其他评论员的建议,提供了很好的答案。根据@JJoao 的建议,我在我的脚本中实现了这两种计算时间,这是一个改进(~3 小时而不是~5 小时)。但是,我只是在进行文本文件操作,所以我看不出它应该花费超过几分钟的时间。所以,我仍在努力更好地利用可用的 CPU,所以我正在修改建议,看看我是否可以进一步加快速度。

更新 2:更正更新 1 我将修改包含到我的脚本中并照此运行,但是我的一大段代码减慢了它的速度。相反,我在目标中间文件上单独运行建议的代码位。这是我看到的:

Time for @Cyrus' sed to complete
real    70m47.484s
user    70m43.304s
sys     0m1.092s

Time for @JJoao's Perl script to complete
real    0m1.769s
user    0m0.572s
sys     0m0.244s

看来我将使用 Perl 脚本。谢谢大家的帮助!

更新 3 这是@Cyrus 改进的 sed 命令所花费的时间:

time sed -f <(sed -E 's|(.*) (.*)|s/^\2/>\1/|' File1 | tr "\n" ";") File2
real    21m43.555s
user    21m41.780s
sys     0m1.140s

【问题讨论】:

  • 如果一个共享名在 File2 中只出现一次,在第一次替换后尝试 sed 上的q 命令停止读取
  • 你可能会觉得这很有趣:unix.stackexchange.com/a/137932/24557
  • 感谢运行时间比较!它表明 Perl 脚本的速度几乎是 Bash 脚本的 70 倍。
  • 这几乎没有意义,但 Perl 脚本实际上只需要不到 2 秒,而 sed 命令需要超过 2100 倍!

标签: bash perl sed parallel-processing fasta


【解决方案1】:

使用 GNU sed 和 bash:

sed -f <(sed -E 's|(.*) (.*)|s/>\2/>\1/|' File1) File2

更新

尝试加快速度:

sed -f <(sed -E 's|(.*) (.*)|s/^>\2/>\1/|' File1 | tr "\n" ";") File2

【讨论】:

  • 太棒了!只是一个建议:sed -f &lt;(sed -E 's|(.*) (.*)|s/&gt;\2\\&gt;/&gt;\1/|' File1) File2 ---- 避免前缀替换。
  • 我真的很喜欢这个简洁的命令。有时我不需要过多关注包含通过此命令进行文件操作的脚本。所以从长远来看,我可能最终会使用这个命令,并使用 Perl 脚本进行紧急计算。
  • @Fatt:在第二个版本中,我添加了 ^| tr "\n" ";"
  • @Cyrus 感谢您的第二个建议。我用改进的命令所花费的时间更新了我的原始帖子。这确实是一种改进。
【解决方案2】:
#!/usr/bin/perl

use strict;
my $file1=shift;
my %dic=();

open(F1,$file1) or die("cant find replcmente file\n");
while(<F1>){                       # slurp File1 to dic
  if(/(.*)\s*(.*)/){$dic{$2}=$1}
}

while(<>){                         # for all File2 lines
  s/(?<=>)(.*)/ $dic{$1} || $1/e;  # sub ">id" by >dic{id}
  print
}

我更喜欢@cyrus 解决方案,但如果您需要经常这样做,您可以使用以前的 perl 脚本(chmod + install)作为 一个字典替换命令。

用法:dict-replacement File1 File* &gt; output

如果您能告诉我们各种解决方案的时间,那就太好了...

【讨论】:

    猜你喜欢
    • 2013-04-13
    • 2011-04-27
    • 2011-10-23
    • 1970-01-01
    • 2014-07-16
    • 1970-01-01
    • 2021-10-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多