Grep 与多线程
Grep with multi-threading
我有以下包含 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 个线程的一部分,所以我该如何修改它(使用 parallel
或 xargs
?)以便它在我想要指定的线程数上 运行?
你的想法是错误的,使用shell循环来处理文本。您正在打开一个新的文件描述符,用于为输入文件上的每个 30233088 迭代重定向到输出文件。它很容易产生巨大的性能影响或 运行 超出打开的文件描述符的情况。
使用正确的工具来完成工作。 Awk
是你的朋友。如果 sequence.txt
只是一个巨大的模式,就像你说的那样,你可以将它放入一个变量中进行正则表达式匹配,如下所示。这些解决方案不涉及必须将条目存储在 RAM
中的内存开销
awk -v sequence="$(<sequence.txt)" 'n=index(sequence, ){print n":"}' mystringfile.txt
这应该比你的方法相对更快,为了进一步加快速度,更改你的 locale
设置以匹配 C
本地,
LC_ALL=C awk -v sequence="$(<sequence.txt)" 'n=index(sequence, ){print n":"}' mystringfile.txt
要与 grep
的 -b
选项匹配以打印字节偏移量开始,请在上面的答案中使用 n-1
而不是仅 n
。
如果您仍想使用 GNU 并行,请使用 --pipepart
将文件物理拆分成多个部分并指定 --block
大小到要读取多少 MB 的文件内容
parallel -a mystringfile.txt --pipepart --block=20M -q awk -v sequence="$(<sequence.txt)" 'n=index(sequence, ){print n":"}'
如果您在 mystringfile.txt
中的所有搜索字符串都具有相同的长度(就像在您的示例文件中一样,16 字节),您可以将 sequence.txt
中的所有 16 字节字符串存储到关联数组(如果您有内存)并加快搜索速度。让我们试试吧。首先我们需要一些测试 material,让我们创建一个 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
and mystringfile.txt
with 30233088 16 byte search strings (4 mins 50 secs):
$ 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()-15 # length-15 16 byte strings coming up
for(i=1;i<=l;i++) { # using l as variable name is stupid
s=substr([=12=],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
in a { # if search string is found
print a[], # output index and string
}' sequence.txt mystringfile.txt
将 2400000 字节 sequence.txt
存储到哈希中花费了 13 秒,并在我的迷你笔记本电脑上使用了 721 MB 的内存。整个脚本 运行 35 秒,发现大约 17000 次点击。
我有以下包含 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 个线程的一部分,所以我该如何修改它(使用 parallel
或 xargs
?)以便它在我想要指定的线程数上 运行?
你的想法是错误的,使用shell循环来处理文本。您正在打开一个新的文件描述符,用于为输入文件上的每个 30233088 迭代重定向到输出文件。它很容易产生巨大的性能影响或 运行 超出打开的文件描述符的情况。
使用正确的工具来完成工作。 Awk
是你的朋友。如果 sequence.txt
只是一个巨大的模式,就像你说的那样,你可以将它放入一个变量中进行正则表达式匹配,如下所示。这些解决方案不涉及必须将条目存储在 RAM
awk -v sequence="$(<sequence.txt)" 'n=index(sequence, ){print n":"}' mystringfile.txt
这应该比你的方法相对更快,为了进一步加快速度,更改你的 locale
设置以匹配 C
本地,
LC_ALL=C awk -v sequence="$(<sequence.txt)" 'n=index(sequence, ){print n":"}' mystringfile.txt
要与 grep
的 -b
选项匹配以打印字节偏移量开始,请在上面的答案中使用 n-1
而不是仅 n
。
如果您仍想使用 GNU 并行,请使用 --pipepart
将文件物理拆分成多个部分并指定 --block
大小到要读取多少 MB 的文件内容
parallel -a mystringfile.txt --pipepart --block=20M -q awk -v sequence="$(<sequence.txt)" 'n=index(sequence, ){print n":"}'
如果您在 mystringfile.txt
中的所有搜索字符串都具有相同的长度(就像在您的示例文件中一样,16 字节),您可以将 sequence.txt
中的所有 16 字节字符串存储到关联数组(如果您有内存)并加快搜索速度。让我们试试吧。首先我们需要一些测试 material,让我们创建一个 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
and mystringfile.txt
with 30233088 16 byte search strings (4 mins 50 secs):
$ 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()-15 # length-15 16 byte strings coming up
for(i=1;i<=l;i++) { # using l as variable name is stupid
s=substr([=12=],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
in a { # if search string is found
print a[], # output index and string
}' sequence.txt mystringfile.txt
将 2400000 字节 sequence.txt
存储到哈希中花费了 13 秒,并在我的迷你笔记本电脑上使用了 721 MB 的内存。整个脚本 运行 35 秒,发现大约 17000 次点击。