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

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

25.07.2017, 10:16. Показов 2581. Ответов 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 / 1913 / 763
Регистрация: 27.07.2012
Сообщений: 5,557
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
Ответ Создать тему
Новые блоги и статьи
Thinkpad X220 Tablet — это лучший бюджетный ноутбук для учёбы, точка.
Programma_Boinc 23.12.2025
Рецензия / Мнение/ Перевод Ниже машинный перевод статьи The Thinkpad X220 Tablet is the best budget school laptop period . Thinkpad X220 Tablet — это лучший бюджетный ноутбук для учёбы,. . .
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Как объединить две одинаковые БД Access с разными данными
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru