Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.92/13: Рейтинг темы: голосов - 13, средняя оценка - 4.92
0 / 0 / 0
Регистрация: 12.06.2017
Сообщений: 12

Медленная работа regex

25.07.2017, 10:16. Показов 2624. Ответов 11
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Всем привет. Делаю небольшую программку для парсинга логов больших размеров. Столкнулся с такой проблемой, что выполнение программы медленное.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
#include <iostream>
#include <fstream>
#include <cstring>
#include <stdio.h>
#include <vector>
#include <clocale>
#include <windows.h>
#include <time.h>
#include <conio.h>
#include <regex>
#include <iterator>
 
 
 
using namespace std;
 
struct ip{
    string ip_address;
    int ipCountNum = 1;
} temp1, temp2;
 
vector<ip> ip_mass;
bool ex = false;
int strNum = 0;
 
void helpStr(){
    wcout << "Использование:" << endl;
    wcout << L" textlogs [path] [regexp]" << endl;
    wcout << "Сделал Владислав Долгирев." << endl;
}
 
void sortFunc(){
    {
        double f = 1.247f;
        int step = ip_mass.size()-1;
        while(step>1){
            for(int i = 0;i+step<ip_mass.size();++i){
                if(ip_mass[i].ipCountNum<ip_mass[i+step].ipCountNum){
                    temp2 = ip_mass[i+step];
                    ip_mass[i+step] = ip_mass[i];
                    ip_mass[i] = temp2;
                }
            }
            step/=f;
        }
        for(int i = 0;i<ip_mass.size();++i){
            bool swapped = false;
            for(int j=0;j<ip_mass.size()-i-1;++j){
                if(ip_mass[j].ipCountNum<ip_mass[j+1].ipCountNum){
                    temp2 = ip_mass[j+1];
                    ip_mass[j+1] = ip_mass[j];
                    ip_mass[j] = temp2;
                    swapped = true;
                }
            }
            if(swapped = false){
                break;
            }
        }
    }
}
 
void insIpMas(string checked){
    bool flag = true;
    for(int i = 0;i<ip_mass.size();i++){
        if(checked == ip_mass[i].ip_address){
            ip_mass[i].ipCountNum++;
            flag = false;
            break;
        }
    }
    if(flag){
        temp1.ip_address = checked;
        ip_mass.push_back(temp1);
    }
}
 
void countFunc(char *argv[]){
    string filePath = argv[1];
    ifstream textFile(filePath, ios::binary);
    if(!textFile.is_open()){
        wcout << "Файл не найден!" << endl;
        ex = true;
        return;
    }
 
    string regexp = argv[2];
    regex reg{regexp};
    smatch result_mass;
    char * buffer = new char [1024*1024];
    while(!textFile.eof()){
        textFile.read(buffer, 1024*1024);
        string buffer_s = buffer;
        sregex_iterator rBeg(buffer_s.begin(), buffer_s.end(), reg);
        sregex_iterator rEnd;
        for(sregex_iterator i = rBeg;i!=rEnd;i++){
            smatch a = *i;
            insIpMas(a[a.size()-1]);
        }
    }
 
    delete buffer;
    textFile.close();
}
 
void outFunc(){
    {
        cout << endl;
        int massSize = 100;
        if(ip_mass.size()<100)
            massSize = ip_mass.size();
        for(int i = 0;i<massSize;i++){
            cout << i+1 << "     " << ip_mass[i].ipCountNum << "     " << ip_mass[i].ip_address << endl;
        }
    }
        cout << "\n";
}
 
int main(int argc, char* argv[]){
    setlocale(LC_ALL, "");
    LARGE_INTEGER freq;
    LARGE_INTEGER t1;
    LARGE_INTEGER t2;
    if(!QueryPerformanceFrequency(&freq)){
        wcout << "Счётчик монитора производительности не поддерживается системой" << endl;
        return 0;
    }
    QueryPerformanceCounter(&t1);
    if(argc == 1){
        helpStr();
        return 0;
    }
    else if(argc == 2){
        return 0;
    }
    else if(argc > 3){
        return 0;
    }
    string regexp = argv[2];
    try{
        regex reg(regexp);
    }
    catch(const regex_error& e){
        switch(e.code()){
            case (regex_constants::error_backref): return 0; break;
            case (regex_constants::error_badbrace): return 0; break;
            case (regex_constants::error_badrepeat): return 0; break;
            case (regex_constants::error_brace): return 0; break;
            case (regex_constants::error_brack): return 0; break;
            case (regex_constants::error_collate): return 0; break;
            case (regex_constants::error_complexity): return 0; break;
            case (regex_constants::error_ctype): return 0; break;
            case (regex_constants::error_escape): return 0; break;
            case (regex_constants::error_paren): return 0; break;
            case (regex_constants::error_range): return 0; break;
            case (regex_constants::error_space): return 0; break;
            case (regex_constants::error_stack): return 0; break;
            default:;
        }
    }
    countFunc(argv);
    if(ex)
        return 0;
    if(ip_mass.size() == 0){
        wcout << "Нет совпадений" << endl;
        return 0;
    }
    sortFunc();
    outFunc();
    QueryPerformanceCounter(&t2);
    double dt = t2.QuadPart - t1.QuadPart;
    double et = 1000*dt/freq.QuadPart;
    wcout << "Строк обработано: " << strNum << endl;
    wcout << "Время выполнения: " << et/1000 << " s" << endl;
}
Медленным куском кода оказался этот:
C++
1
2
3
4
        for(sregex_iterator i = rBeg;i!=rEnd;i++){
            smatch a = *i;
            insIpMas(a[a.size()-1]);
        }
Он увеличивает время работы программы аж на 15 секунд (Функция внутри данного цикла работает быстро). В итоге, лог в 1 млн строк парсится 17 секунд. До этого делал через regex_search, но там вообще выполнение шло больше минуты. Для сравнения, на JScript данный лог парсится 7 секунд, причём по содержанию две утилитки одинаковы. Есть ли какие-то способы ещё увеличить скорость? Компилятор MinGW 5.1.0.
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
25.07.2017, 10:16
Ответы с готовыми решениями:

Boost Regex, работа с указателями
Доброго, пытаюсь разобраться с boost::regex и для удобства решил написать обертку под boost::regex_search(...) Но возникли некие вопросы,...

Regex - работа с файлом
Добрый день! Хочу распарсить стартовую страничку META, счачал и сохранил ее в текстовый файл &quot;meta.txt&quot; с помощью WinInet.h,...

Aser v5 i7 u - очень медленная загрузка системы и такая же медленная работа приложений
Всем привет. Полгода назад купил ноут ( aser v5 i7 u) . Все было нормально, но неделю назад начал не много тормозить, всегда долго...

11
2393 / 1922 / 763
Регистрация: 27.07.2012
Сообщений: 5,562
25.07.2017, 11:43
Ну разве что по классическим заповедям писать ++i. Ну и строку в функцию по ссылке передавать.
0
93 / 69 / 22
Регистрация: 17.10.2011
Сообщений: 235
25.07.2017, 12:03
можно делать все сравнения за один проход, и хранить все частичные совпадения до текущей позиции, для этого нужны только индекс начала частичного совпадения и индекс текущей позиции
0
зомбяк
 Аватар для TRam_
1585 / 1219 / 345
Регистрация: 14.05.2017
Сообщений: 3,940
25.07.2017, 12:55
И ещё
C++
1
insIpMas((*i)[i->size()-1]);
Добавлено через 8 минут
Потому что в
C++
1
smatch a = *i;
производится копирование содержимого *i в а, при вызове
C++
1
void insIpMas(string checked)
в checked копируется содержимое a[a.size()-1]. Чтобы копирование не производилось, нужна передача по ссылке или по указателю.
0
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
25.07.2017, 19:34
Цитата Сообщение от XJIE6yIIIEK Посмотреть сообщение
Есть ли какие-то способы ещё увеличить скорость?
1.
компилять релиз в режиме оптимизации по скорости,
а не дебаг с 100500 всевозможных проверок.

2.
если это не поможет, тогда уже можно начинать потрошить код.
всякие такие места:

Цитата Сообщение от XJIE6yIIIEK Посмотреть сообщение
for(int i = 0;i<ip_mass.size();++i){
если размер коллекции не изменяется,
количество элементов можно закэшировать.
это может помочь компилятору оптимизировать цикл


Цитата Сообщение от XJIE6yIIIEK Посмотреть сообщение
if(checked == ip_mass[i].ip_address){
айпишник можно представить в виде целого числа.
а не сравнивать каждый раз строки

Цитата Сообщение от XJIE6yIIIEK Посмотреть сообщение
void insIpMas(string checked){
ссылки? не, не слышал.

Цитата Сообщение от XJIE6yIIIEK Посмотреть сообщение
temp1.ip_address = checked;
* * * * ip_mass.push_back(temp1);
emplace_back
за такой код вообще убивать нужно

Цитата Сообщение от XJIE6yIIIEK Посмотреть сообщение
textFile.read(buffer, 1024*1024);
отключайте синхронизацию с сишными потоками.

почитайте на досуге:
https://habrahabr.ru/post/246257/
0
0 / 0 / 0
Регистрация: 12.06.2017
Сообщений: 12
26.07.2017, 09:19  [ТС]
Цитата Сообщение от hoggy Посмотреть сообщение
если размер коллекции не изменяется
Размер массива изменяется.

в ip_mass может закидываться не только ip, то что было задано regexp`ом, то и идёт в массив (Изначально была задача только ip парсить, а потом задача поменялась).

Цитата Сообщение от hoggy Посмотреть сообщение
отключайте синхронизацию с сишными потоками.
Метод read() читает файл в 1 млн. строк блоками по мегабайту за 12ms. Текстовый файл в 4гб читает за 31ms. Выигрышь в пару ms будет, как капля в море.

Добавлено через 17 минут
Применил все советы, что мне дали, но в итоге время выполнения изменилось на 100 ms. В конце концов, самым лагающим куском кода так и остался цикл for(sregex_iterator i = rBeg;i!=rEnd;++i). даже если закомментить функцию внутри него, то время выполнения будет меньше на 157ms. Делал ещё вариант:
C++
1
2
3
4
while(rBeg != rEnd){
     //Функция
     ++rBeg;
}
Но он оказался медленнее. на 7s.
Чем быстрым можно заменить пробег по итератору, я не могу придумать.
0
зомбяк
 Аватар для TRam_
1585 / 1219 / 345
Регистрация: 14.05.2017
Сообщений: 3,940
26.07.2017, 14:47
Вероятно дело в том, что регулярное выражение интерпретируется, а не компилируется. Для того, чтоб оно использовалось в скопилированном виде, нужна библиотека наподобие http://blablacode.ru/programmirovanie/63 , но в этом случае регурлярное выражение должно быть задано дефайном, а не передаваться через argv[2] .

Ну а чтобы программа компилировала свои же куски во время выполнения - такое и антивирус может заблокировать, и компилятор пришлось бы вовнутрь встраивать. В общем для скорости скорее всего придётся отказаться от ввода выражений в командной строке.
0
2784 / 1937 / 570
Регистрация: 05.06.2014
Сообщений: 5,602
26.07.2017, 20:29
Цитата Сообщение от XJIE6yIIIEK Посмотреть сообщение
Есть ли какие-то способы ещё увеличить скорость?
1) Флаг std::regex_constants::optimize.
2) Другой движок.
Цитата Сообщение от TRam_ Посмотреть сообщение
Вероятно дело в том, что регулярное выражение интерпретируется, а не компилируется.
Или в том что ТС познакомился с catastrophic backtracking. Методы защиты есть, как минимум если в выражении нет backreference. Пользовались ли этими методами авторы движка - другой вопрос.
0
 Аватар для avgoor
1550 / 877 / 179
Регистрация: 05.12.2015
Сообщений: 2,555
27.07.2017, 02:30
Цитата Сообщение от XJIE6yIIIEK Посмотреть сообщение
Текстовый файл в 4гб читает за 31ms
Т.е. 4*8/0.031 = 1032 Гбит-а в секунду (при максимальной скорости sata3 - 6 Гбит/с)? У вас рэйд массив из 172-х винчестеров будущего?
0
зомбяк
 Аватар для TRam_
1585 / 1219 / 345
Регистрация: 14.05.2017
Сообщений: 3,940
27.07.2017, 02:41
avgoor, вероятно речь о 31 секунде. Если прикинуть по
Цитата Сообщение от XJIE6yIIIEK Посмотреть сообщение
файл в 1 млн. строк блоками по мегабайту за 12ms
1024*4*12 = 49 152 (плюс минус лапоть сходится)
0
 Аватар для avgoor
1550 / 877 / 179
Регистрация: 05.12.2015
Сообщений: 2,555
27.07.2017, 02:54
TRam_, Да нет. Судя по тексту, где речь идет о семи секундах и "выигрыш в пару ms - как капля в море".
Скорее всего, намерял погоду на марсе, или мерял отдельно, отключив обработку, и оптимизатор просто выпилил КЕМ чтение файла.
0
0 / 0 / 0
Регистрация: 12.06.2017
Сообщений: 12
28.07.2017, 08:30  [ТС]
Всё, проблема решена. Убрал флаг -pg при компиляции и всё отрабатывает за 5s.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
28.07.2017, 08:30
Помогаю со студенческими работами здесь

Медленная работа с БД
Есть MS SQL-2008 на неплохом железе - ОЗУ 96 Гб. На нём есть база CRM Dynamics. Счёт записям идёт на миллионы в основных таблицах. Работают...

медленная работа
Подскажите, пожалуйста, в чем причина. На одном из компов в сети медленная скорость работы программ 1С и инфо-бухгалтер, комп находится в...

Медленная работа 1С
Народ работает в терминале Есть сервер, i5-4460, 32GB, hdd Пользователей много потому решили купить новый сервер E5-2650 v4, 128 GB,...

Медленная работа с БД
Две программы на Delphi обращаются к одной БД. Проблема в том, что когда одна программа вносит изменения, вторая программа видит эти...

Медленная работа в 1с по сети
В офисе 4 компьютера, 1С-Предприятие работает быстро только на 1ом основном компьютере. На остальных подбор по справочнику, проведение...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
12
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Синхронизация спрайтов SDL3 и тел Box2D
8Observer8 04.03.2026
Содержание блога Финальная демка в браузере. Итоговый код: finish-sync-physics-sprites-sdl3-c. zip На первой гифке отладочные линии отключены, а на второй включены:. . .
SDL3 для Web (WebAssembly): Идентификация объектов на Box2D v3 - использование userData и событий коллизий
8Observer8 02.03.2026
Содержание блога Финальная демка в браузере. Итоговый код: finish-collision-events-sdl3-c. zip https:/ / www. cyberforum. ru/ blog_attachment. php?attachmentid=11680&amp;d=1772460536 Одним из. . .
Реалии
Hrethgir 01.03.2026
Нет, я не закончил до сих пор симулятор. Эта задача сложнее. Не получилось уйти в плавсостав, но оно и к лучшему, возможно. Точнее получалось - но сварщиком в палубную команду, а это значит, в моём. . .
Ритм жизни
kumehtar 27.02.2026
Иногда приходится жить в ритме, где дел становится всё больше, а вовлечения в происходящее — всё меньше. Плотный график не даёт вниманию закрепиться ни на одном событии. Утро начинается с быстрых,. . .
SDL3 для Web (WebAssembly): Сборка библиотек: SDL3, Box2D, FreeType, SDL3_ttf, SDL3_mixer и SDL3_image из исходников с помощью CMake и Emscripten
8Observer8 27.02.2026
Недавно вышла версия 3. 4. 2 библиотеки SDL3. На странице официальной релиза доступны исходники, готовые DLL (для x86, x64, arm64), а также библиотеки для разработки под Android, MinGW и Visual Studio. . . .
SDL3 для Web (WebAssembly): Реализация движения на Box2D v3 - трение и коллизии с повёрнутыми стенами
8Observer8 20.02.2026
Содержание блога Box2D позволяет легко создать главного героя, который не проходит сквозь стены и перемещается с заданным трением о препятствия, которые можно располагать под углом, как верхнее. . .
Конвертировать закладки radiotray-ng в m3u-плейлист
damix 19.02.2026
Это можно сделать скриптом для PowerShell. Использование . \СonvertRadiotrayToM3U. ps1 <path_to_bookmarks. json> Рядом с файлом bookmarks. json появится файл bookmarks. m3u с результатом. # Check if. . .
Семь CDC на одном интерфейсе: 5 U[S]ARTов, 1 CAN и 1 SSI
Eddy_Em 18.02.2026
Постепенно допиливаю свою "многоинтерфейсную плату". Выглядит вот так: https:/ / www. cyberforum. ru/ blog_attachment. php?attachmentid=11617&stc=1&d=1771445347 Основана на STM32F303RBT6. На борту пять. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru