Модераторы: javastic, AntonSaburov

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Оптимизация скорости поиска по огромному файлу 
:(
    Опции темы
drMIG
Дата 12.3.2009, 14:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 16
Регистрация: 23.2.2009

Репутация: 1
Всего: 1



Есть огромный файл CSV. Надо реализовать поиск по нему, т.е. если в строке встретилось всё (объединены логическим И), что записано в строке поиска, то приостановить поиск и вывести записи на экран, при нажатии далее возобновить поиск.
Подскажите можно ли как-то оптимизировать алгоритм. Сейчас поиск записи по 7-и метровому фалу занимает около минуты на эмуляторе, не говоря уже про обычный телефон.

Сейчас алгоритм следующий:
Открываем файл, читаем его в цикле, используя InputStreamReader (в коде -- reader).

Код

while ((a = reader.read()) != -1){
     currPosition++;
     //построчное чтение
     if (a != '\r' & a != '\n'){
     //решаем проблему с кодировкой
                    if ((a>=0xc0)&&(a<=0xff))
                    {b.append((char)(a+0x350));}
                    else if(a==0xa8){b.append((char)(0x401));}
                    else if(a==0xb8){b.append((char)(0x451));}
                    else
                    {b.append((char)(a));}                    
                    continue;}
       //прочитали строку
       else
                { 
                    //поместили текущую строку в resString
                    String resString=b.toString();
                    //самописная функция (она есть в моем посте про чтение из файла)
                    //переводит в верхний регистр всё, в том числе и русские буквы
                    String sString = toUpperRus(resString);
                    //число совпадений (должно быть найдено в строке всё из строки поиска)
                    int numbComp=0;
                    //fString -- массив, содержащий отдельные куски строки поиска (разбитые по  
                    //пробелу)
                    for(int i=0; i < fString.length;i++)
                    {
                    if (sString.indexOf(fString[i].toString())>0)
                        {
                            numbComp++;          
                        }
                    }
                    //если совпало всё, выводим результат
                    if (numbComp==fString.length && numbComp>0) {
                       String strRes[] = split(removeChar(resString, '"'),";");
                       for (int k=0; k < strRes.length;k++){
                            try {
                            String pnumber=strRes[k];
                            Long.parseLong(pnumber); 
                            im=Image.createImage("/tel.png");
                            }
                            catch (Exception ex) {im=null;}
                           results.append(strRes[k], im);
                       }
                       results.setSelectedIndex(0, true);
                       break;
                    }
                    else
                    {
                        if ((currPosition)==currFileSize){
                            results.append("Поиск не дал результатов", null);
                            EndOfSearch=true;
                            break;
                         }
                    }
                    b = new StringBuffer("");
                   }

}


Подскажите узкие места кода, где и как можно оптимизировать скорость выполнения.
PM MAIL   Вверх
Platon
Дата 12.3.2009, 15:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1801
Регистрация: 25.4.2006

Репутация: нет
Всего: 40



У меня 3 предложения, которые лишь на 5-10% могут увеличить скорость.

Код

b = new StringBuffer("");

1. Не знаю есть ли в JME StringBuilder, но его использовать предпочтительней.
2. Предлагаю не плодить объекты, а просто чистить (по-моему clear())
3. 
Код

String strRes[] = split(removeChar(resString, '"'),";");

Возможно вам стоит избавиться от этой функции. Попробуйте "на лету" составлять запись.

Добавлено через 5 минут и 33 секунды
"На лету" подразумеваю следующее
1. читаем символ
2. (разделитель полей)? (Добавляем в буферный объект считанное поле) : 
__3. (разделитель строк)? (Обрабатываем буферный объект, затем чистим его, готовя к новой операции формирования записи) :
____4. (продолжаем формировать текущее поле)

Добавлено через 6 минут и 47 секунд
Посмотрите, возможно в JME есть BufferedReader, он может читать построчно.
PM MAIL ICQ   Вверх
eugine_s
Дата 12.3.2009, 16:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 581
Регистрация: 14.11.2007
Где: Киев

Репутация: 17
Всего: 17




Ну для начала 7мб файл - много, поэтому быстро скорее всего никак не сделаешь. Но ускорить можно и на мой взгляд ускорить можно за счет уменьшения количества создаваемых объектов (а именно строк и stringbuffer-ов)
    
например, как Platon написал, вот это: 
Код

b = new StringBuffer("");

заменить на очистку b

Пересмотреть метод: 
Код

toUpperRus()

Из того что я видел в другом посте в этом методе используется: String += (char); (добавление символа к строке) - это действие эквивалентно созданию новой строки, поэтому заменить String на StringBuffer и добавлять символы в него.

Так же пересмотреть всякие .toString методы - это тоже создание новой строки.

Цитата(Platon @  12.3.2009,  15:34 Найти цитируемый пост)
1. Не знаю есть ли в JME StringBuilder, но его использовать предпочтительней.


нет такого

Цитата(Platon @  12.3.2009,  15:34 Найти цитируемый пост)
Посмотрите, возможно в JME есть BufferedReader, он может читать построчно. 


тоже нет такого
PM MAIL   Вверх
math64
Дата 12.3.2009, 16:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2505
Регистрация: 12.4.2007

Репутация: 8
Всего: 72



Это будет ресурс в jar или файл в памяти телефона? Если ресурс, его лучше переформатировать и порезать на куски перед помещением в jar.
Кстати, в телефоне программа может работать быстрее, чем в эмуляторе (зависит от модели телефона и компьютера)
PM   Вверх
drMIG
Дата 12.3.2009, 17:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 16
Регистрация: 23.2.2009

Репутация: 1
Всего: 1



Ок, спасибо. Это всё учту.

Ещё ко всему этому была подкинута идея (не знаю насколько реальная, во всяком случае не совсем понимаю пока как её реализовать по причине плохого знания основ работы с потоками:( ) -- чтение из файла в буфер, в нескольких потоках, схематично представленная так:

Код

char a;
char buffer; // consider using more than one buffer...
buffer = reader.read(); // consider reading into buffer in a separate thread
while (buffer != -1) {
  a = buffer; // ready to use in search, doesn't have to wait while char is read
  // prepare buffer for next iteration
  buffer = reader.read(); // consider reading into buffer in a separate thread
  doTheSearchStuff(a); // all the code that does the search, "currPosition++ etc"
}


math64, нет в том-то и дело, что отдельный файл(ы), лежащий(е) на флешке в телефоне. Необходимо предоставить интерфейс для поиска по ним в виде мидлета.

Ещё несколько вопросов:
1. Эммм... А как, кстати, очистить StringBuffer? Ничего более подходящего кроме b.setLength(0); не нашел. Это правильно?
2. Что касается сбора строк (из строк и символов) -- каково быстродействие у следующих методов и когда их лучше использовать? 
   а. Функция String.concat()
   б. Функция StringBuffer.append() с последующим StringBuffer.toString();
   в. Использование += (кстати, str+="ddd" эквивалентно str=str+"ddd"?) 


Это сообщение отредактировал(а) drMIG - 12.3.2009, 17:22
PM MAIL   Вверх
eugine_s
Дата 12.3.2009, 19:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 581
Регистрация: 14.11.2007
Где: Киев

Репутация: 17
Всего: 17



Цитата(drMIG @  12.3.2009,  17:04 Найти цитируемый пост)
2. Что касается сбора строк (из строк и символов) -- каково быстродействие у следующих методов и когда их лучше использовать? 
   а. Функция String.concat()
   б. Функция StringBuffer.append() с последующим StringBuffer.toString();
   в. Использование += (кстати, str+="ddd" эквивалентно str=str+"ddd"?) 



a и в - создание новой строки

Вот реализация append в WTK: 
Код

    public synchronized StringBuffer append(char str[])
    {
        int len = str.length;
        int newcount = count + len;
        if(newcount > value.length)
            expandCapacity(newcount);
        System.arraycopy(str, 0, value, count, len);
        count = newcount;
        return this;
    }

т.е. если у тебя не вызывается expandCapacity() то точно быстрее будет выполняться


Цитата(drMIG @  12.3.2009,  17:04 Найти цитируемый пост)
1. Эммм... А как, кстати, очистить StringBuffer? Ничего более подходящего кроме b.setLength(0); не нашел. Это правильно?


ну или удалять все содержимое.


PM MAIL   Вверх
math64
Дата 13.3.2009, 09:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2505
Регистрация: 12.4.2007

Репутация: 8
Всего: 72



Я думаю, стоит создать свой Reader сразу конвертирующий байты в нужную кодировку и добавляющий буферизацию.
А можно наоборот, эталонные строки сконвертировать в массивы байт и искать по байтам, а конвертировать байты в строки только при успешном сравнении.
PM   Вверх
drMIG
Дата 13.3.2009, 19:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 16
Регистрация: 23.2.2009

Репутация: 1
Всего: 1



Да, с конвертированием строк это тоже хорошая идея. Возможно, отсутствие конвертирования исходных строк увеличит скорость. Гораздо легче один раз привести к нужному виду строку для поиска. Учту это.

А что вы всё-таки думаете по поводу чтения из нескольких потоков? Т.е. создаем класс-читалку, работающую как отдельный поток, в которую передаём начальную и конечную позицию для чтения. Запускаем несколько экземпляров. Т.е. одновременно идёт чтение сразу из нескольких мест файла. Когда какой-то экземпляр находит соответствие строке поиска, он отдаёт результат для отображения и продолжает работать. Я конечно понимаю, что на телефоне процессор не многоядерный, но хотя бы субъективную скорость выполнения это увеличит? И если да, то как оптимально подобрать количество потоков для чтения?
PM MAIL   Вверх
Platon
Дата 13.3.2009, 19:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1801
Регистрация: 25.4.2006

Репутация: нет
Всего: 40



Я думаю для JME дохлый номер.

Добавлено через 3 минуты и 26 секунд
И вообще:
1. Потоков должно быть не больше числа процессоров
2. Потоков должно быть не больше числа считывающих головок в ПЗУ
PM MAIL ICQ   Вверх
W0LF
Дата 14.3.2009, 02:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


alexander lonsky
***


Профиль
Группа: Участник
Сообщений: 1164
Регистрация: 9.2.2006
Где: Ukraine.Dnepropet rovsk

Репутация: 19
Всего: 20



не больше числа процессоров? 
Platon, чего?
а как насчет ограничения в 10000 потоков в винде? в фрибсди там конечно по-другому, я конечно понимаю что процессоров не 10000, НО, все ведь эмулируется, есть процесс, есть в нем потоки и тп. в j2me я обычно использовал не более трех одновременно запущенных потоков

Это сообщение отредактировал(а) W0LF - 14.3.2009, 02:05


--------------------
iOS developer
PM MAIL WWW Skype GTalk   Вверх
Platon
Дата 14.3.2009, 11:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1801
Регистрация: 25.4.2006

Репутация: нет
Всего: 40



W0LF
а что не так? разумно использовать потоков в задаче по числу процессоров. или мои представления об архитектуре мобильных устройств не актуальны?
PM MAIL ICQ   Вверх
W0LF
Дата 15.3.2009, 03:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


alexander lonsky
***


Профиль
Группа: Участник
Сообщений: 1164
Регистрация: 9.2.2006
Где: Ukraine.Dnepropet rovsk

Репутация: 19
Всего: 20





--------------------
iOS developer
PM MAIL WWW Skype GTalk   Вверх
drMIG
Дата 1.4.2009, 22:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 16
Регистрация: 23.2.2009

Репутация: 1
Всего: 1



Итог: чтение посимвольно слишком медленное впринципе, даже если вообще убрать все, кроме самого чтения. Значительное ускорение на ПК и незначительное ускорение на телефоне было достигнуто использованием для чтения функции readUTF (предварительно была написана утилитка для ПК, конвертирующая исходный файл соответствующим образом, аналогичным функции writeUTF). Значительное увеличение скорости дает лишь способ чтения:
Код

byte[] bb = new byte [1024];
while (data.read(bb)!=-1) {
...
}

Отсюда вопросы: 
1. Как оптимально подобрать размер байтового массива
2. Собственно, как искать. Исходные данные: массив bb и строка, которую ищем fString.
PM MAIL   Вверх
Platon
Дата 2.4.2009, 10:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1801
Регистрация: 25.4.2006

Репутация: нет
Всего: 40



1. Смотрите на объем памяти планируемых устройств + проанализируйте сколько байт разом считывает метод read(). Не гарантируется, что массив байт будет полностью заполнен, даже если не достигнут конец файла.
2. 
Цитата(Platon @  12.3.2009,  16:34 Найти цитируемый пост)
"На лету" подразумеваю следующее
1. читаем символ
2. (разделитель полей)? (Добавляем в буферный объект считанное поле) : 
__3. (разделитель строк)? (Обрабатываем буферный объект, затем чистим его, готовя к новой операции формирования записи) :
____4. (продолжаем формировать текущее поле)

можно приметить и к сконвертированной строке.

PM MAIL ICQ   Вверх
drMIG
Дата 4.4.2009, 13:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 16
Регистрация: 23.2.2009

Репутация: 1
Всего: 1



По поводу 2 -- да, но возникает очччень большая проблема, связанная с регистронезависимым (с учетом регистра все ищется довольно быстро) поиском -- преобразование строки, по которой осуществляется поиск, к одному регистру занимает недопустимо много времени.
PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса

  • Прежде чем задать вопрос прочтите это!
  • Литература по Java находится здесь.
  • Литературу по Java обсуждаем здесь.
  • Используйте теги [code=java][/code] для подсветки кода. Используйтe чекбокс "транслит" (возле кнопок кодов) если у Вас нет русских шрифтов.
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда

  • FAQ раздела лежит здесь!
 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Java ME (J2ME) | Следующая тема »


 




[ Время генерации скрипта: 0.0943 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.