具有多线程的Grep

时间:2018-11-09 08:42:48

标签: awk parallel-processing grep xargs

我有以下具有30233088字符串的(大)文件:

head mystringfile.txt:

GAATGAACACGAAGAA
GAATGAACACGAAGAC
GAATGAACACGAAGAG
GAATGAACACGAAGCA

cat sequence.txt

AAATAGAGGGCGGTCCAGGCGTGTCGAAACACTGGGTCCAGGGCAAGAGCGGTTCGGGTGTCAGGAAAGCCCCCAAGGGGGTTCGCGCGGTTTGCAGTGAGGTAGAGGCCGGTGTATGGGTAGACAATTGGGGTCCCAAAGAAAAAGGCTCGTCCAACATCATAATAAACCCAAGCACGATAAAAAGCAAACGCAGACTTCAATAGGGTACGAGCAATTGTGGCAGGGTGCTCGCTGTCAGGGTTAGATCTTCTTGGAGTCGCGTCGCTCGGGGGGGCAAGGCCAACGTAAGATCGTGGCTGATCGCTGGCAATGCGGTCGGTTGGGTGGTCGCTAGTAGGGGCACGGCGGTCTCTTATGGCGTCGTAAAATGCGTCTCCAAAGCGAAAAGGGGCGGCAGACAAGTCACCGGGCAAGCTTAGAGGTCTGGGGCCCGTGGCTTTAGGGGAATGAACACGAAGACGCGAAACGAAGTCGTGTTTCTTGTTGGCTGTAGAGGGGAAAACCGTCTGGGGCGATCTGGCGTAGTAGTGCGTGTCTTGCAGTGAGCTCCCCGTCCGTAAGGATTCGCAGGAATCCTGCGTGAAGCTCGGTCGTCTCGGCCGTGTCTCGGGGTTTGATTGCGGGTTCAGATTGGAAAGGTCTCCTCGGGTCGTTTGCTGCATTTGCTCGCAACCCTGACGTGAAAGGGGTGAGCTGTCTCCAATCTGCCACGCTGGGTGTTGCGTCGTCAGTAAAAGACTTGGTCAAGCTGGGACCTCGCAAGATCGCGAGAGGGTTAAGCACAAAAGGTATGGCGAAGCTCCCGGGTGCTCTTGTGGCCACCCAGAATCATGGTGACGTAGGTTTTGCGAAGCCATCAAAAATTCAGGCGGCAAAACGAGCCAGTAGGGTCCTGGGCAGCTGGGCTTGTAGTGGGTAGGCGGCAAAACGCAAAGAATGAACACGAAGCAACTCCGTAGTGTGACGGGGGTTCTGACAAACGTCCTGCAAGAAGTTCGTCTTGGG

我需要在另一个序列文件中grep来确定比赛的位置,具体操作如下:

while read line; do grep -b -o $line sequence.txt >>sequence.txt.count; done<mystringfile.txt

像这样运行代码当然会花费很长时间,并且只运行1个线程的一部分,那么如何修改它(使用parallelxargs?)以便在上面运行我要指定多少个线程?

2 个答案:

答案 0 :(得分:3)

使用shell循环处理文本,您的想法是错误的。您正在打开一个新的文件描述符,以针对输入文件上的30233088迭代中的每个迭代重定向到输出文件。这很可能会对性能产生巨大影响,或者容易导致打开的文件描述符用尽。

使用正确的工具进行作业。 Awk是您的朋友在这里。如果您所说的sequence.txt只是一个巨大的模式,则可以将其插入到正则表达式匹配的变量中,如下所示。该解决方案不涉及将条目存储在RAM中的内存开销

awk -v sequence="$(<sequence.txt)" 'n=index(sequence, $1){print n":"$1}' mystringfile.txt

这应该比您所采用的方法相对更快,并且为了进一步加快速度,请更改locale设置以匹配C本地

LC_ALL=C awk -v sequence="$(<sequence.txt)" 'n=index(sequence, $1){print n":"$1}' mystringfile.txt

要与grep的{​​{1}}选项匹配以打印字节偏移开始,请在上面的答案中使用-b而不是n-1

如果您仍要使用GNU并行,请使用n将文件物理拆分为多个部分,并指定--pipepart大小以读取多少MB的文件内容

--block

答案 1 :(得分:2)

如果您在 mystringfile.txt 中的所有搜索字符串都具有相同的长度(例如在示例文件中为16个字节),则可以存储所有16个字节从sequence.txt到关联数组(如果有内存)的字符串,并加快了搜索速度。让我们尝试一下。首先,我们需要一些测试材料,让我们创建一个2400000字节的sequence.txt,大约需要一秒钟:

$ awk -v seed=$RANDOM 'BEGIN{a[0]="A";a[1]="C";a[2]="G";a[3]="T";srand(seed);for(i=1;i<=2400000;i++)printf "%s", a[int(4*rand())];print ""}' > mystringfile.txt

mystringfile.txt和30233088 16字节搜索字符串(4分钟50秒):

$ awk -v seed=$RANDOM 'BEGIN{a[0]="A";a[1]="C";a[2]="G";a[3]="T";srand(seed);for(i=1;i<=30233088;i++){for(j=1;j<=16;j++)printf "%s", a[int(4*rand())];print ""}}' > mystringfile.txt

然后是脚本:

$ awk '
NR==FNR {                              # process the sequence file
    l=length($1)-15                    # length-15 16 byte strings coming up
    for(i=1;i<=l;i++) {                # using l as variable name is stupid
        s=substr($0,i,16)              
        a[s]=a[s] (a[s]==""?"":",") i  # hash string start indexes to a, string as key
    }                                  # a["ACTGTGCACGTATAGC"]=3,141,592
    next
}                                      # the search part 
$1 in a {                              # if search string is found
    print a[$1], $1                    # output index and string
}' sequence.txt mystringfile.txt

将2400000字节的sequence.txt存储到哈希中需要13秒,并且在我的微型笔记本电脑上使用了721 MB的内存。整个脚本运行了35秒,发现了约17000次点击。