Улучшить скорость моего bash-кода - PullRequest
0 голосов
/ 29 ноября 2011

Ниже приведен формат файла, с которым мне нужно иметь дело:

@HWI-ST150_0129:2:1:4226:2616#0/1
CATCTTTTCTCTTAACTTCCATGATGGTACATCTTTTGATTTTTTTTTAATAACGTCTTTGACAGCTTAAATTCTTTTTCAAAATC
+HWI-ST150_0129:2:1:4226:2616#0/1
d\dddddaddbcad^\^a\]ZZZ_`]\VYa_bZ^_^\YX\X`eeeeffffffefffeeefffefffeeffBBBBBBBBBBBBBBBB

В основном мне нужно сделать следующее: 1. выбрать каждую 4-ю строку; и обрежьте все возможные конечные "B" в конце строки.

2.Если левая часть составляет> 70% всей строки после обрезки, то: обрезать дубликат в каждой 2-й строке для последовательности "B" в 4-й строке.

3. Затем просто добавьте все 4 строки со второй и четвертой обрезкой.

Итак, ожидаемый результат выглядит следующим образом:

@HWI-ST150_0129:2:1:4226:2616#0/1
CATCTTTTCTCTTAACTTCCATGATGGTACATCTTTTGATTTTTTTTTAATAACGTCTTTGACAGCTTAA
+HWI-ST150_0129:2:1:4226:2616#0/1
d\dddddaddbcad^\^a\]ZZZ_`]\VYa_bZ^_^\YX\X`eeeeffffffefffeeefffefffeeff

И я написал скрипт вроде:

for((a=1;a<=8000000;a++))
do
  if (($a%4==0))
  then  
      b=`cat $FILENAME|head -$a|tail -1|sed 's/\(.\)B*$/\1/g'|wc -c`
      d=`cat $FILENAME|head -$a|tail -1|wc -c`
      if (( 10*$b/$d>= 7 ))
      then
          cat $FILENAME|head -$(($a-3))|tail -1
          cat $FILENAME|head -$(($a-2))|tail -1|cut -b 1-$(($b-1))
          cat $FILENAME|head -$(($a-1))|tail -1
          cat $FILENAME|head -$a|tail -1|sed 's/\(.\)B*$/\1/g'
      fi
  fi
done >> /home/xxx/$DIRNAME/$FILENAME

Я думаю, что предпочитаю bash-код просто потому, что он быстрый (?). Тем не менее, когда я запускаю этот код, он медлит, думая о 8000000 строк. Кроме того, может быть, я слишком часто использовал "cat" в коде?

быстро, я имею в виду, скажем, при использовании команд разделения для разделения большого файла на уровне ГБ; это супер супер быстро. (Какой механизм раскола?)

Есть предложения по улучшению скорости?

Ответы [ 4 ]

2 голосов
/ 29 ноября 2011

Измените свою логику, чтобы она работала так:

1) Читайте в 4 строки.

2) Обработайте 4 строки, которые вы прочитали.

3) Записьиз результатов вашей обработки

4) Повтор.

Ваш код проходит файл шесть раз за каждый проход.Тебе нужно пройти только один раз за все.

1 голос
/ 29 ноября 2011

Я думаю, что часть проблемы может заключаться в том, что на каждой итерации цикла for вы будете кататься / заголовать / что бы то ни было весь текстовый файл ... который, я думаю, будет источником узкого места.

Удаление кошки, вероятно, не сделает это намного быстрее, поскольку вы каждый раз вызываете другие команды unix для него.

Возможно, вы захотите найти решение, которое может просто прочитатьфайл один раз и произведет необходимый вывод, а не прочитав его 8 000 000 * 6 раз.(1 против 48 000 000! :))

Вот идея:

f = OPEN_FILE() //Some file descriptor
out_f = NEW_FILE_FOR_WRITING() //open some file to write to
while not_eof(f):
    cur_window = read_four_lines(f) //Get four lines from the text thing
    modified_block = do_stuff(cur_window) //Do your processing in a different function
    write(out_f,modified_block) //Write the modified stuff to the output file

Я не уверен, какой язык вам наиболее удобен, но это не должно быть слишком сложносделать.Я полагаю, что это возможно в bash-скрипте с несколькими изменениями.

0 голосов
/ 21 января 2012

Дэвид прав. Действительно неэффективно анализировать один и тот же большой файл более одного раза. Кроме того, запуск всех этих внешних программ также снижает производительность.

Вот простая реализация логики, предоставленной Дэвидом в bash только с одной внешней командой на цикл:

#!/bin/bash
DONE=false
until $DONE ; do
read -r LINE1 || DONE=true
read -r LINE2 || DONE=true
read -r LINE3 || DONE=true
read -r LINE4 || DONE=true

NEWLINE4=`echo $LINE4 |sed 's/\(.\)B*$/\1/g'`
NEWLINE2=${LINE2:0:${#NEWLINE4}}

echo $LINE1
echo $NEWLINE2
echo $LINE3
echo $NEWLINE4

done

Это очень просто и имеет несколько ошибок (в конце печатаются 4 пустые строки), которые легко исправить. Этот код должен быть во много раз быстрее, чем ваша первая версия.

0 голосов
/ 29 ноября 2011

Вы можете использовать ~ для внесения изменений в каждую 4-ю строку с помощью sed.Если вы намерены обрезать весь трейлинг B на каждой 4-й строке вашего INPUT_FILE, просто выполните -

Например:

[jaypal:~/Temp] cat file
1
2
3
4
5
6
7
8
9
10

[jaypal:~/Temp] sed '0~4 s/[0-9]/bbbb/' file
1
2
3
bbbb
5
6
7
bbbb
9
10
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...