Модераторы: Daevaorn

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Обработать строку самым быстрым образом. 
V
    Опции темы
Хоббит
Дата 18.1.2009, 10:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


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

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



Есть строка, представляющая алгебраическое выражение. Строка очень большая, в перспективе до сотен мегабайт (возможно это уже не строка а файл на диске, в котором есть выражении и их него происходит считывание данных). Необходимо одно подвыражение в строке разбить и заменить другим.
К примеру 3 + fn(a1, l, c1) + 4 * fn(a1, l, c2) - 5 * fn(a3, l, c3)
Заменить на 3 + f1a1 + 4 * f2a1 - 5 * f3a3
Использовал для строки класс string, а для поиска и операций find, replace, substr.
Профайлер показывает, что на эту замену уходит до 60% времени программы. Хотелось бы оптимизировать операции. Я так понимаю придется работать с char* (C строки).

Как самым быстрым образом, выполнять поиск в С строках, извлекать подстроку и соединять строки. Так же, как бы вы предложили выделять память под новые строки.

Пока все это так
Код

        // Позиция с которой идет поиск.
        int startPosition = 0;
        // Позиция следующей фунции.
    int fnPosition;
        // Префикс выражения.
    string fnPrefix("f");

        // Ищем по всей строке, начиная с текущей позиции.
    while ((fnPosition = value.find("fn(", startPosition)) != string::npos)
    {
                // Определяем позицию первого параметра.
        int parameterPosition = fnPosition + 3;
                // Определяем позицию первой запятой.
        int firstComaPosition = value.find(",", parameterPosition);

                // Определяем длину параметра.
        int parameterNameLength = firstComaPosition - parameterPosition;

                // Вырезаем первый параметр.
        string parameterName = value.substr(parameterPosition, parameterNameLength);

                // Определяем позицию второй запятой.
        int secondComaPosition = value.find(",", firstComaPosition + 1);
                // Определяем опзицию закрывающей скобки.
        int closeBracketPosition = value.find(")", secondComaPosition + 1);

                // Определяем длины 3го параметра
        int orderLength = closeBracketPosition - secondComaPosition - 1;
                
                // Вырезаем третий параметр.
        string order = value.substr(secondComaPosition + 1, orderLength);

                // Получаем имя нового подвыражения
        string name = fnPrefix + order + parameterName;

                // Производим замену
        value.replace(fnPosition, closeBracketPosition + 1 - fnPosition, name);
                 
                // Переходим к следующей позиции
        startPosition = fnPosition + 1 + orderLength + parameterNameLength;
    }
    return value;

PM MAIL   Вверх
vinter
Дата 18.1.2009, 10:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Explorer
****


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

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



Цитата(Хоббит @  18.1.2009,  11:28 Найти цитируемый пост)
Я так понимаю придется работать с char* (C строки).

кто тебе сказал, что с ними будет быстрее работать?


--------------------
Мой блог
PM MAIL WWW   Вверх
Хоббит
Дата 18.1.2009, 10:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


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

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



Я предположил. К примеру при конкатенации строк, каждый раз вычисляется длина строки, эта операции чуть ли не самая долгая из всех. Работаю с char* я смогу хранить указатель на конец строки и организовать свой метод конкатенации строк. Подействует?
PM MAIL   Вверх
vinter
Дата 18.1.2009, 12:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Explorer
****


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

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



Цитата(Хоббит @  18.1.2009,  11:59 Найти цитируемый пост)
Я предположил. К примеру при конкатенации строк, каждый раз вычисляется длина строки, эта операции чуть ли не самая долгая из всех. Работаю с char* я смогу хранить указатель на конец строки и организовать свой метод конкатенации строк. Подействует?

скорее всего length() \представляет собой end-begin, так что все работает быстро. Я лично не проверял, но не вижу почему std::string может работать медленее. Поимщи, на форуме было сравнение скорости работы, и если мне память не изменяет работа со string получалась быстрее.



--------------------
Мой блог
PM MAIL WWW   Вверх
Kallikanzarid
Дата 18.1.2009, 12:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


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

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



Делать замену в строке такого размера - самоубийство. Лучше сразу пиши в файл вывода то, что нужно.
PM MAIL   Вверх
Alexeis
Дата 18.1.2009, 12:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Амеба
Group Icon


Профиль
Группа: Админ
Сообщений: 11743
Регистрация: 12.10.2005
Где: Зеленоград

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



  Операции replace, substr и конкатинация действительно медленные. Было дело, что мне удалось увеличить скорость не менее чем в 4 раза заменив wstring на TCHAR* , но дело было не просто в замене, а в том что при помощи TCHAR* удобно делать низкоуровневые оптимизации. Кроме того можно выиграть если все выделения памяти внутри цикла производить не в куче, а в специальном пуле (как в стеке), т.е. память освободиться только по выходу из цикла целиком.
  Бить нужно в выделения памяти. Оператор "+" это выделение памяти с копированием, replace это выделение памяти с еще большим копированием, substr выделение памяти с небольшим копированием. Компиляторы С++ чаще всего имеют фиговенькие менеджеры куч, потому операция выделения памяти весьма не быстрая.


--------------------
Vit вечная память.

Обсуждение действий администрации форума производятся только в этом форуме

гениальность идеи состоит в том, что ее невозможно придумать
PM ICQ Skype   Вверх
mes
Дата 18.1.2009, 13:49 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


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

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




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



--------------------
PM MAIL WWW   Вверх
Lycifer
Дата 18.1.2009, 14:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


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

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



Если говорить об оптимизации то явно STL не оптимизирована. 
Оптимизация работы с памятью это сложный вопрос(как правило включается зависимость железа)
 - разворот циклов на чтение.запись памяти
 - Как читается указатель
Вообщем очень много , советую почитать литературу.
PM MAIL ICQ   Вверх
Хоббит
Дата 18.1.2009, 15:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


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

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



Понравился совет mes. В принципе сам пришел к такому же решению. Попробую, скажу результат.
Если в дальнейшем не будет хватать памяти, организую это все через файлы и потоки.
PM MAIL   Вверх
Хоббит
Дата 18.1.2009, 17:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


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

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



Второй вариант.

Код

        int length = value.length();
    const char* in = value.c_str();
    char* out = new char[length];
    
    int inIndex = 0;
    int outIndex = 0;
    
    int parameterNamePosition;
    int firstComaPosition;
    int secondComaPosition;
    int closeBracketPosition;
    int parameterNameLength;
    int orderLength;
    
    while (inIndex < length)
    {
        if (in[inIndex] == '\'')
        {
            inIndex += 2;
            parameterNamePosition = inIndex;
            
            while (in[inIndex++] != ',');
            firstComaPosition = inIndex - 1;
            
            while (in[inIndex++] != ',');
            secondComaPosition = inIndex - 1;
            
            while (in[inIndex++] != ')');
            closeBracketPosition = inIndex - 1;
                        
            parameterNameLength = firstComaPosition - parameterNamePosition - 1;
            orderLength = closeBracketPosition - secondComaPosition - 1;
            
            out[outIndex++] = 'f';
            memcpy(out + outIndex, in + secondComaPosition + 1, orderLength);
            outIndex += orderLength;
            
            memcpy(out + outIndex, in + parameterNamePosition + 1, parameterNameLength);
            outIndex += parameterNameLength;            
            
            inIndex = closeBracketPosition + 1;            
        }
        out[outIndex++] = in[inIndex++];        
    }
    
    out[outIndex] = '\0';
    value = string(out);
    
    delete[] out;
    
    return value;


Выигрыша во времени НЕТ! Мои надежды не оправдались.

Добавлено через 29 секунд
Видно нужны другие подходы.
PM MAIL   Вверх
mes
Дата 18.1.2009, 18:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


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

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



...

Это сообщение отредактировал(а) mes - 18.1.2009, 18:15


--------------------
PM MAIL WWW   Вверх
xvr
Дата 18.1.2009, 20:48 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

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



Для такой задачи нужно кардинально другой метод обработки - нужно не перепахивать многократно всю строку для каждой fn, а делать все замены на одном проходе (можно даже на лету, не сохраняя собственно строку). Ищи по ключевым словам regex, NFA, DFA

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


Шустрый
*


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

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



Цитата(Хоббит @ 18.1.2009,  17:57)
Второй вариант....Выигрыша во времени НЕТ! Мои надежды не оправдались...

во втором варианте вы делаете проход побайтно!!! smile а в первом вы вызываете ОПТИМИЗИРОВАННУЮ функцию поиска подстроки(если ничего не попутал то что видел)...

естественней будет медленней. и странно что то же самое получили smile видать тест не длинный...

постарайтесь использовать приведённые тут советы..и помните..
1) функции из библиотек обрабатываемые скопом инфу - оптимизированные на низком уровне...наверняка поиск символа в строке будет в коде звучать типа substr т.е. быстрее вряд ли придумаешь...
2) постарайтесь измерять и проанализировать где ЯВНО у вас встречаються тормоза...и можно ли эти участки сделать паралельно. Т.е. например поиск подстрок выражений - скопом, а вот обработку их отдельно - в потоках. грамотная ось будет давать выигрыш в скорости даже на одном проце с одним конвеером(к сожалению форточки к этим осям не относяться) ...
3) постарайтесь глобально проанализировать задачу...возможно решение в лоб (поиск и замена) - не есть оптимум к результату... может имеет смысл искать начало и конец этих функций на момент создания(вставки) , информацию сохранять и потом именно её и кушать на входе?


удачи Вам
(круглый)
PM MAIL   Вверх
kshyms
Дата 29.1.2009, 08:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 303
Регистрация: 30.8.2006
Где: Душанбе

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



Цитата

Необходимо одно подвыражение в строке разбить и заменить другим
 по моему trim сгодится
PM MAIL WWW Skype   Вверх
GoldFinch
Дата 29.1.2009, 11:57 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата



****


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

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



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

PM MAIL ICQ   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




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


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

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