как быстро файл проверить на правильность символов
От: pvnic  
Дата: 03.04.02 07:47
Оценка:
Здравствуйте!

Вот какая проблема — есть файл(порядка 1.5 мега, но это небольшой еще) из него нужно выбрать только те сиволы, которые принадлежат — atgc
но изначально, там есть разная дополнительная информация+форматирование+цифры
как из всего этого безобразия взять только символы из того алфавита?
сейчас код примерно такой:

    // second step  - load
    do
    {
        getline( is, data );
        const char* lpData = data.c_str();
        if (data.size()>1 && lpData[0] == '/' && lpData[1] == '/' )
            break;
        else
        {
            int len = data.length();
            for(int i=0; i<len; i++)   
            {
                switch(data[i])
                {
                    case 'a':
                        m_iCountA++;
                        clearedData+='a';
                        break;
                    case 'A':
                        m_iCountA++;
                        clearedData+='a';
                        break;
                    case 'c':
                        m_iCountC++;
                        clearedData+='c';
                        break;
                    case 'C':
                        m_iCountC++;
                        clearedData+='c';
                        break;
                    case 'g':
                        m_iCountG++;
                        clearedData+='g';
                        break;
                    case 'G':
                        m_iCountG++;
                        clearedData+='g';
                        break;
                    case 't':
                        m_iCountT++;
                        clearedData+='t';
                        break;
                    case 'T':
                        m_iCountT++;
                        clearedData+='t';
                        break;
                    default: 
                         break;
                }
            }
            body += clearedData;
        }

но заметно тормозит.....
Re: как быстро файл проверить на правильность символов
От: Boroda Россия  
Дата: 03.04.02 08:00
Оценка:
Здравствуйте pvnic, Вы писали:

P>Здравствуйте!


P>Вот какая проблема — есть файл(порядка 1.5 мега, но это небольшой еще) из него нужно выбрать только те сиволы, которые принадлежат — atgc

P>но изначально, там есть разная дополнительная информация+форматирование+цифры
P>как из всего этого безобразия взять только символы из того алфавита?
P>сейчас код примерно такой:

P>
P>    // second step  - load
P>    do
P>    {
P>        getline( is, data );
P>        const char* lpData = data.c_str();
P>        if (data.size()>1 && lpData[0] == '/' && lpData[1] == '/' )
P>            break;
P>        else
P>        {
P>            int len = data.length();
P>            for(int i=0; i<len; i++)   
P>            {
P>                switch(data[i])
P>                {
P>                    case 'a':
P>                        m_iCountA++;
P>                        clearedData+='a';
P>                        break;
P>                    case 'A':
P>                        m_iCountA++;
P>                        clearedData+='a';
P>                        break;
P>                    case 'c':
P>                        m_iCountC++;
P>                        clearedData+='c';
P>                        break;
P>                    case 'C':
P>                        m_iCountC++;
P>                        clearedData+='c';
P>                        break;
P>                    case 'g':
P>                        m_iCountG++;
P>                        clearedData+='g';
P>                        break;
P>                    case 'G':
P>                        m_iCountG++;
P>                        clearedData+='g';
P>                        break;
P>                    case 't':
P>                        m_iCountT++;
P>                        clearedData+='t';
P>                        break;
P>                    case 'T':
P>                        m_iCountT++;
P>                        clearedData+='t';
P>                        break;
P>                    default: 
P>                         break;
P>                }
P>            }
P>            body += clearedData;
P>        }

P>

P>но заметно тормозит.....


Первое что пришло в голову ...

разбить файл на нескоько равных частей.
Запустить столько же threads.
В каждой нитке считать m_iCountXXX.
После завершения всё складываем.

Скорость будет зависеть из отношений длина файла и кол-во threads.
Dimok
Re: как быстро файл проверить на правильность символов
От: Bell Россия  
Дата: 03.04.02 08:05
Оценка:
Здравствуйте pvnic, Вы писали:

P>но заметно тормозит.....


Можно попробовать перед for написать

clearedData.reserve(len);

вполне возможно, что внутри этого for-а при вызове operator+=() несколько раз происходит reallocate, что в общем случае не способствует повышению производительности
Любите книгу — источник знаний (с) М.Горький
Re[2]: как быстро файл проверить на правильность символов
От: Кодт Россия  
Дата: 03.04.02 08:23
Оценка:
Здравствуйте Boroda, Вы писали:

P>>Вот какая проблема — есть файл(порядка 1.5 мега, но это небольшой еще) из него нужно выбрать только те сиволы, которые принадлежат — atgc

P>>но изначально, там есть разная дополнительная информация+форматирование+цифры
P>>как из всего этого безобразия взять только символы из того алфавита?

{skipped}

Во-первых, acgt — это не нуклеотиды ли?

Во-вторых. Самые тормоза — в строчке
body += clearedData

Что требует перевыделения памяти.

Как существенно ускорить процесс.

1) выделять выходной буфер по-блочно. можно просто писать в write-only поток.
2) читать файл по-блочно (или вообще отобразить его в память).

С многопоточностью, imho, лучше не заморачиваться — накладные расходы на синхронизацию (на однопроцессорной машине).

3) переписать switch:
int alpha = -1; // индекс буквы в алфавите
switch(read_letter())
{
case 'a': case 'A': alpha = 0; break;
case 'c': case 'C': alpha = 1; break;
case 'g': case 'G': alpha = 2; break;
case 't': case 'T': alpha = 3; break;
}

if(alpha < 0) // не то что надо
  continue;

m_iCount[alpha]++; // счетчики по алфавиту

static const char letters[] = "acgt"; // алфавит в lower-case

write_letter( letters[alpha] );

где псевдофункции read_letter & write_letter могут быть реализованы как вам угодно.

---

Если файл можно зачитать в память одним махом, то чтение-запись делается так (напр.)
char* buffer;
unsigned bufsize;

read_file(&buffer, &bufsize);

const char* reader = buffer;
const char* writer = buffer;
unsigned remains = bufsize;

while(remains)
{
  char letter = *(reader++); remains--;

  int alpha = -1;
  switch(letter)
  {
  case 'A': letter = 'a'; // заодно переведем в lowercase
  case 'a': alpha = 0;
    break;
  // аналогично остальные
  }

  m_iCounts[alpha]++;

  // запись
  *(writer++) = letter;
}

write_file(buffer, (writer-buffer));

read_file & write_file — это может быть чтение файла или его маппирование — на усмотрение.
Перекуём баги на фичи!
Re[3]: как быстро файл проверить на правильность символов
От: Аноним  
Дата: 03.04.02 08:36
Оценка:
Здравствуйте Кодт, Вы писали:

К>Здравствуйте Boroda, Вы писали:


P>>>Вот какая проблема — есть файл(порядка 1.5 мега, но это небольшой еще) из него нужно выбрать только те сиволы, которые принадлежат — atgc

P>>>но изначально, там есть разная дополнительная информация+форматирование+цифры
P>>>как из всего этого безобразия взять только символы из того алфавита?

К>{skipped}


К>Во-первых, acgt — это не нуклеотиды ли? ;)

они самые:)

спасибо за развернутый ответ, прийду домой попробую.
Re[3]: как быстро файл проверить на правильность символов
От: Kaa Украина http://blog.meta.ua/users/kaa/
Дата: 03.04.02 08:54
Оценка:
Здравствуйте Кодт, Вы писали:

К>3) переписать switch:

Не! Выкинуть его вообще! Вместо этого пользовать

strchr( <алфавит>, <текущий_символ> ). Будет заметно побыстрее.
Алексей Кирдин
Re[3]: как быстро файл проверить на правильность символов
От: flyker Россия  
Дата: 03.04.02 09:38
Оценка:
Здравствуйте Кодт, Вы писали:

К>Здравствуйте Boroda, Вы писали:


P>>>Вот какая проблема — есть файл(порядка 1.5 мега, но это небольшой еще) из него нужно выбрать только те сиволы, которые принадлежат — atgc

P>>>но изначально, там есть разная дополнительная информация+форматирование+цифры
P>>>как из всего этого безобразия взять только символы из того алфавита?

К>{skipped}


К>Во-первых, acgt — это не нуклеотиды ли?


К>Во-вторых. Самые тормоза — в строчке

К>
К>body += clearedData
К>

К>Что требует перевыделения памяти.

К>Как существенно ускорить процесс.


К>1) выделять выходной буфер по-блочно. можно просто писать в write-only поток.

К>2) читать файл по-блочно (или вообще отобразить его в память).

К>С многопоточностью, imho, лучше не заморачиваться — накладные расходы на синхронизацию (на однопроцессорной машине).


К>3) переписать switch:

К>
К>int alpha = -1; // индекс буквы в алфавите
К>switch(read_letter())
К>{
К>case 'a': case 'A': alpha = 0; break;
К>case 'c': case 'C': alpha = 1; break;
К>case 'g': case 'G': alpha = 2; break;
К>case 't': case 'T': alpha = 3; break;
К>}

К>if(alpha < 0) // не то что надо
К>  continue;

К>m_iCount[alpha]++; // счетчики по алфавиту

К>static const char letters[] = "acgt"; // алфавит в lower-case

К>write_letter( letters[alpha] );
К>

К>где псевдофункции read_letter & write_letter могут быть реализованы как вам угодно.

К>---


К>Если файл можно зачитать в память одним махом, то чтение-запись делается так (напр.)

К>
К>char* buffer;
К>unsigned bufsize;

К>read_file(&buffer, &bufsize);

К>const char* reader = buffer;
К>const char* writer = buffer;
К>unsigned remains = bufsize;

К>while(remains)
К>{
К>  char letter = *(reader++); remains--;

К>  int alpha = -1;
К>  switch(letter)
К>  {
К>  case 'A': letter = 'a'; // заодно переведем в lowercase
К>  case 'a': alpha = 0;
К>    break;
К>  // аналогично остальные
К>  }

К>  m_iCounts[alpha]++;

К>  // запись
К>  *(writer++) = letter;
К>}

К>write_file(buffer, (writer-buffer));
К>

К>read_file & write_file — это может быть чтение файла или его маппирование — на усмотрение.

Самое слабое место в его алгоритме это getline, именно оно все тормозит.
Нужно использовать _read, а все остальное по большому счету по барабану как написано.
Все гениальное — просто
Re[4]: как быстро файл проверить на правильность символов
От: Кодт Россия  
Дата: 03.04.02 10:01
Оценка:
Здравствуйте Kaa, Вы писали:

Kaa>Здравствуйте Кодт, Вы писали:


К>>3) переписать switch:

Kaa>Не! Выкинуть его вообще! Вместо этого пользовать

Kaa>strchr( <алфавит>, <текущий_символ> ). Будет заметно побыстрее.


С какой радости это будет быстрее чем свитч?
По любому 8 сравнений + сравнение с нулем — концом строки.

Компактнее — да. Но для 4-буквенного алфавита это несерьезно.

Самое быстрое — это бинарный поиск
A?
  < error!
  > a?
    < G?
      < C?
        != error!
      > T?
        != error!
    > g?
      < c?
        != error!
      > t?
        != error!
Перекуём баги на фичи!
Re[4]: как быстро файл проверить на правильность символов
От: Boroda Россия  
Дата: 03.04.02 10:25
Оценка:
Здравствуйте Kaa, Вы писали:

Kaa>Здравствуйте Кодт, Вы писали:


К>>3) переписать switch:

Kaa>Не! Выкинуть его вообще! Вместо этого пользовать

Kaa>strchr( <алфавит>, <текущий_символ> ). Будет заметно побыстрее.


А лучше и это выкинуть! Вместо этого пользовать
strpbrk(<строка>,<алфавит>);
Dimok
Re[5]: как быстро файл проверить на правильность символов
От: Кодт Россия  
Дата: 03.04.02 10:46
Оценка:
Здравствуйте Boroda, Вы писали:

B>А лучше и это выкинуть! Вместо этого пользовать

B>strpbrk(<строка>,<алфавит>);

А все равно быстрее не получится (мне кажется).
Потому что сначала мы каждый символ проверяем на вхождение в алфавит (внутри strpbrk).
а потом, если нашли, — начинаем анализировать, что это за символ и что с ним делать.

Грамотно писаная программа + оптимизирующий компилятор.
Перекуём баги на фичи!
Re[5]: как быстро файл проверить на правильность символов
От: Kaa Украина http://blog.meta.ua/users/kaa/
Дата: 03.04.02 10:47
Оценка:
Здравствуйте Boroda, Вы писали:

Я проверил: со свитчем ничто сравниться не может. у моего способа он на 5000000 итераций в 4-5 раз выигрывает. Беру свои слова обратно.

С уважением
Алексей Кирдин
Re: как быстро файл проверить на правильность символов
От: Аноним  
Дата: 04.04.02 09:31
Оценка:
у тебя скорее всего тормозит чтение файла. сделай бинарное чтение (_read()).
а вообще, зачем ты гадаешь? запускай VTune и там смотри, где тормоза расположены.

а чтобы убрать switch сделай предварительно массивчик на 256 элементов, сбрось его
в 0, а элементы 'a','t','g','c','A','T','G','C' установи в 1,2,3,4,1,2,3,4.
При чтении файла используй считанный символ как индекс в этом массиве.
При этом из массива сразу получишь номер буквы (0-skip, 1-a,2-t,3-g,4-c).
А дальше этот номер используй как хочешь (как индекс в массиве счетчиков, например; как условие для if и т.п.)
надеюсь идея ясна.
Re[6]: как быстро файл проверить на правильность символов
От: zaiats_2k Россия  
Дата: 04.04.02 12:45
Оценка:
Вы не о том спорите, ребята. В switchах оптимизировать нечего, ибо потери не там происходят. Как уже было справедливо указано основные потери происходят в строчках
 clearedData+='a';

потому как при этом часто приходится буфер переразмещать.

И это при том, что промежуточный буфер тут вообще не нужен!!!
do
    {
        getline( is, data );
        const char* lpData = data.c_str();
        if (data.size()>1 && lpData[0] == '/' && lpData[1] == '/' )
            break;
        else
        {
            int len = data.length();
            int c=0; 
            for(int i=0; i<len; i++)   
            {
                switch(data[i])
                {
                    case 'a':
                    case 'A':
                        m_iCountA++;
                        data[c] ='a'; c++;
                        break;
                    // Тоже самое для остальных букв
                }
            }
           // По выходе из цикла первые c символов data содержат нужные данные,
            // обрезаешь data до этого размера и ...
            data.resize(c);
            body += data;
        }
0 программистов ругал сердитый шеф,
потом уволил одного, и стало их FF!
Re[7]: как быстро файл проверить на правильность символов
От: Кодт Россия  
Дата: 04.04.02 13:32
Оценка:
Здравствуйте zaiats_2k, Вы писали:

Z2>Вы не о том спорите, ребята. В switchах оптимизировать нечего, ибо потери не там происходят.


Z2>И это при том, что промежуточный буфер тут вообще не нужен!!!


И об этом тоже было сказано

.....
data[c] ='a'; c++;
.....
// По выходе из цикла первые c символов data содержат нужные данные,
// обрезаешь data до этого размера и ...
data.resize(c);
body += data;[/b]
Z2>


Во-первых, все равно получается промежуточный буфер, хотя и более редко обновляемый.
Во-вторых, работа с STL — это динамическое выделение памяти, а следовательно, не быстрое.

---

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

Если размеры файлов — многие мегабайты, а плотность нуклеотидов мала, то, наверное, удобнее сначала переписать файл (например, во временный файл со 100% плотностью), а потом юзать уже его.

Или сделать обертку, которая из файла последовательно читает только нужное.

char getACGT(FILE* src);
int getACGTs(FILE* src, char* dst, int size);


Смотря по тому, как используются полученные данные.
Перекуём баги на фичи!
Re[8]: как быстро файл проверить на правильность символов
От: zaiats_2k Россия  
Дата: 04.04.02 13:48
Оценка:
Я просто сказал в чём была проблема в приведённом в исходном постинге участке кода.

Можно продолжить решать задачу в общем виде или для различных экстремальных случаев... Но нужно ли это спрашивающему? IMHO нет, если он ещё не разобрался в том что скрывается за basic_string::operator+=
0 программистов ругал сердитый шеф,
потом уволил одного, и стало их FF!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.