Grep с многопоточностью - PullRequest
       32

Grep с многопоточностью

0 голосов
/ 09 ноября 2018

У меня есть следующий (большой) файл со строками 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?), Чтобы он выполнялся на столько потоков, сколько Я хочу уточнить?

Ответы [ 2 ]

0 голосов
/ 10 ноября 2018

Если все строки поиска в 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 МБ памяти на моем мини-ноутбуке. Весь сценарий работал 35 секунд и обнаружил около 17000 обращений.

0 голосов
/ 09 ноября 2018

Ваша идея неверна с использованием цикла оболочки для обработки текста. Вы открываете один новый файловый дескриптор для перенаправления в выходной файл для каждой из 30233088 итераций вашего входного файла. Он подвержен огромному влиянию на производительность или нехватке дескрипторов открытых файлов.

Используйте правильный инструмент для работы. Awk твой друг здесь. Если, как вы говорите, sequence.txt - это просто огромный шаблон, вы можете просто поместить его в переменную для соответствия регулярному выражению, как показано ниже. Решения не требуют дополнительных затрат памяти для хранения записей в ОЗУ

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

Это должно быть относительно быстрее, чем ваш подход, и чтобы ускорить процесс, измените ваши настройки locale, чтобы они соответствовали C local,

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

Чтобы сопоставить с grep опцией -b для печати начала смещения байта, используйте n-1 в ответе выше вместо просто n.

Если вы все еще хотите использовать GNU параллельно, используйте --pipepart, чтобы физически разбить файл на части, и укажите размер --block, сколько МБ содержимого файла для чтения

parallel -a mystringfile.txt --pipepart --block=20M -q awk -v sequence="$(<sequence.txt)" 'n=index(sequence, $1){print n":"$1}'
...