Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.97/35: Рейтинг темы: голосов - 35, средняя оценка - 4.97
 Аватар для bedvit
1210 / 261 / 22
Регистрация: 20.05.2016
Сообщений: 1,147
Записей в блоге: 22

Скорость чтения csv с разных носителей

21.05.2020, 23:27. Показов 10092. Ответов 148
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Добрый день, джентльмены.
На днях набросал простой код поиска нужной строки в CSV-файле, см. под спойлером
Кликните здесь для просмотра всего текста
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
extern "C" __declspec(dllexport) LPXLOPER12  WINAPI FindInCSV(char *  arg1, char *  arg2, wchar_t *  arg3)
{
    LPXLOPER12 OperOut = new XLOPER12;
    OperOut->xltype = xltypeStr | xlbitDLLFree;
    OperOut->val.str = new XCHAR[32767 + 2]; //+1 под размер + 1 под нуль-терминатор
    OperOut->val.str[0] = 0;
    OperOut->val.str[1] = '\0';
    std::filebuf fb;
    if (fb.open(arg1, std::ios::in | std::ios::binary))
    {
        int x = 0;
        int lenStrOut = 0; //0й элемент - размер строки
        int lenArg3 = wcslen(arg3);
        bool overflow = false;
        std::string str;
        std::istream is(&fb);
        XCHAR* strTmp= OperOut->val.str + 1;
 
        while (is) 
        {
            std::getline(is, str);
            size_t found = str.find(arg2);
            if (found != std::string::npos)
            {
                x++;
                if (lenArg3 > 0 && x > 1)
                {
                    if (lenStrOut + lenArg3 > 32767) { overflow = true;  goto end_; }
                    wcscpy(strTmp + lenStrOut, arg3);
                    lenStrOut = lenStrOut + lenArg3;
 
                    if (lenStrOut + str.length() > 32767) { overflow = true;  goto end_; }
                    MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, str.c_str(), -1, strTmp + lenStrOut, str.length() + 1);
                    lenStrOut = lenStrOut + str.length();
                }
                else if (lenArg3 > 0)
                {
                    if (lenStrOut + str.length() > 32767) { overflow = true;  goto end_; }
                    MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, str.c_str(), -1, strTmp + lenStrOut, str.length() + 1);
                    lenStrOut = lenStrOut + str.length();
                }
                else
                {
                    if (lenStrOut + str.length() > 32767) { overflow = true;  goto end_; }
                    MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, str.c_str(), -1, strTmp + lenStrOut, str.length() + 1);
                    lenStrOut = lenStrOut + str.length();
                    goto end_ ;
                }
            };
        }
    end_:
        if (overflow) {
            wcscpy(strTmp, L"Qverflow. Max char 32767\0");
            OperOut->val.str[0] = 24;
        }
        else
        {
            OperOut->val.str[0] = lenStrOut;
        }
        fb.close();
    }
    return OperOut;
}

Сегодня протестировал работу на з-х накопителях:
HDD WDC WD10EACS-00ZJB0 (1000 ГБ, SATA-II)
HDD WDC WD5000AAKX-001CA0 (500 ГБ, 7200 RPM, SATA-III)
SSD KINGSTON SV300S37A120G (120 ГБ, SATA-III)

В итоге время обработки CSW-файла размером 1ГБ у всех примерно одинаковое, что стало для меня откровением. Я предполагал, что в данном коде узкое место скорость чтения с накопителя. Чем можно объяснить такой результат теста?
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
21.05.2020, 23:27
Ответы с готовыми решениями:

Скорость записи и чтения данных с разных источников - из реестра и Json
Всем привет. Возникла необходимость где то хранить данные приложения. Было выбрано два варианта: Реестр JSON Из какого...

Создание тестов на скорость чтения и скорость записи
Проблемка такая - пишу простенький тест на скорость записи и скорость чтения, локальных и съемных дисков. Как написать тесты вроде...

Так ли важна в реальной жизни скорость записи SSD, или смотреть надо только на скорость чтения, а на запись пофигу
https://www.citilink.ru/catalog/computers_and_notebooks/hdd/ssd_in/420250/ вот у него скорость записи низкая, но он самый популярный

148
19505 / 10108 / 2463
Регистрация: 30.01.2014
Сообщений: 17,828
27.06.2020, 23:46
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от bedvit Посмотреть сообщение
Задача на ansi.
На самом деле это не особо влияет, не знаю чего вы так принципиальны к этому. Соотношения-то все равно останутся теми же.
0
19505 / 10108 / 2463
Регистрация: 30.01.2014
Сообщений: 17,828
28.06.2020, 00:07
bedvit, Чуть получше вариант.


Программа: test.zip

Выводы в общем следующие:
1) Функция strstr крайне хорошо оптимизирована в mscrt.
2) VC++ в целом лучше оптимизирует код под платформу Windows.
3) Реализация стандартной библиотеки C++ лучше у MinGW.
0
19505 / 10108 / 2463
Регистрация: 30.01.2014
Сообщений: 17,828
28.06.2020, 00:12
bedvit, вот результаты компиляции и запуска того же кода на VS 2017 у меня
0
 Аватар для bedvit
1210 / 261 / 22
Регистрация: 20.05.2016
Сообщений: 1,147
Записей в блоге: 22
28.06.2020, 11:11  [ТС]
DrOffset, мои результаты.
В целом паритет между std::find и strstr, с незначительным отрывом std::find.
А вот std::search хорошо оптимизирована в MinGW.
Миниатюры
Скорость чтения csv с разных носителей  
0
 Аватар для bedvit
1210 / 261 / 22
Регистрация: 20.05.2016
Сообщений: 1,147
Записей в блоге: 22
28.06.2020, 11:38  [ТС]
Но плохо оптимизирована strstr (в MinGW).
На мой взгляд, вообще не оптимизирована.

Добавлено через 5 минут
И опять же, общее для всех, почему плохо оптимизированы boyer_moore.
Условия явно хорошие, что бы показать хороший результат - но нет.

Добавлено через 13 минут
Цитата Сообщение от bedvit Посмотреть сообщение
В целом паритет между std::find и strstr, с незначительным отрывом std::find.
Извините, ошибся, strstr (VS2017) на порядок быстрее std::find (MinGW).
А сам std::find на VS2017 быстрее чем std::find в MinGW в 3 раза.
DrOffset, у вас похожие результаты.

Добавлено через 6 минут
Цитата Сообщение от DrOffset Посмотреть сообщение
Реализация стандартной библиотеки C++ лучше у MinGW.
только std::search, boyer_moore - паритет, std::find - медленнее в 3 раза.

Итого: на MinGW хорошо реализована std::search, на VS 2017 - std::find, и особенно strstr - в 9-10 раз быстрее ближайших конкурентов.
Откуда такая скорость?
0
19505 / 10108 / 2463
Регистрация: 30.01.2014
Сообщений: 17,828
28.06.2020, 11:58
Вы как-то не очень глубоко поняли мой комментарий.
Цитата Сообщение от bedvit Посмотреть сообщение
на MinGW хорошо реализована std::search
Не только. boyer_moore в MinGW реализован лучше, но проигрывает из-за худшей оптимизации компилятора. Это можно доказать, если перенести код std для boyer_moore в VC++. Но это не слишком тривиальная задача.
Цитата Сообщение от bedvit Посмотреть сообщение
std::find - медленнее в 3 раза.
По той же причине. Насколько я знаю код find в std:: MinGW и VC++ примерно одинаковый. Различия в скорости объясняются работой оптимизатора в компиляторе.

Цитата Сообщение от bedvit Посмотреть сообщение
И опять же, общее для всех, почему плохо оптимизированы boyer_moore.
Это неверные выводы.
Плохо сделано только в VC++. Это дало возможность MinGW практически сравняться с ним, даже при худшей оптимизации компилятора.

Цитата Сообщение от bedvit Посмотреть сообщение
strstr - в 9-10 раз быстрее ближайших конкурентов.
Откуда такая скорость?
А вот это я не знаю. Сам столкнулся с этим первый раз, т.к. обычно VC++ не использую и под Windows ничего не пишу уже лет 12.
1
 Аватар для bedvit
1210 / 261 / 22
Регистрация: 20.05.2016
Сообщений: 1,147
Записей в блоге: 22
28.06.2020, 12:06  [ТС]
Интересно посмотреть - какой выдают результат другие компиляторы.
XLAT, у вас какой? Примите участие в тесте? У меня с вами по-моему не было такого большого отличия в поиске.
0
19505 / 10108 / 2463
Регистрация: 30.01.2014
Сообщений: 17,828
28.06.2020, 12:36
bedvit, немного посмотрел, strstr в VC++ использует инструкции из SSE4. В частности команду PCMPISTRI. Отсюда и скорость.
2
 Аватар для bedvit
1210 / 261 / 22
Регистрация: 20.05.2016
Сообщений: 1,147
Записей в блоге: 22
03.07.2020, 12:25  [ТС]
По теме: допилил код, убрал копирование в буферы, теперь буфер/ы асинхронно заливаются, по очереди.
Обогнал XLAT на std:: на 20%, там где ранее проигрывал - чтение из кеша.
т.е. теперь быстрее во всех вариантах.
XLAT, протестируете?
Ваш компилятор, возможно, покажет другие скорости, по причине слабой оптимизации strstr, но этим и интересен результат.

Кликните здесь для просмотра всего текста
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
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
std::string FindRowsInCSVansi(PCTSTR file, char* findStr, bool multiLine, int fileFlagNoBuffering)
{
    const DWORD  nNumberOfBytesToRead = 16777216;//67108864;//33554432; //16777216;//8388608;//читаем в буфер байты
    size_t findStrLen = strlen(findStr);
    if (findStrLen >= nNumberOfBytesToRead) { return ""; };
 
    // создаем события с автоматическим сбросом
    HANDLE hEndRead = CreateEvent(NULL, FALSE, FALSE, NULL);// дескриптор события
    //if (hEndRead == NULL) { return GetLastError(); }
    if (hEndRead == NULL) { return "";  }
 
    // открываем файл для чтения
    HANDLE hFile = CreateFile(  // дескриптор файла
        file,   // имя файла
        GENERIC_READ,          // чтение из файла
        FILE_SHARE_READ,       // совместный доступ к файлу
        NULL,                  // защиты нет
        OPEN_EXISTING,         // открываем существующий файл
        FILE_FLAG_OVERLAPPED | (fileFlagNoBuffering != 0 ? FILE_FLAG_NO_BUFFERING : FILE_FLAG_RANDOM_ACCESS),// асинхронный ввод//отключаем системный буфер
        NULL                   // шаблона нет
    );
    // проверяем на успешное открытие
    if (hFile == INVALID_HANDLE_VALUE)
    {
        CloseHandle(hEndRead);
        return "";
    }
 
    char* notAlignBuf = new char[nNumberOfBytesToRead *2 + 4096 + 1]; //буфер
    char* buf = notAlignBuf + nNumberOfBytesToRead;; //буфер
    if (size_t(buf) % 4096) { buf += 4096 - (size_t(buf) % 4096); }//адрес принимающего буфера тоже должен быть выровнен по размеру сектора/страницы 
 
    char* notAlignBufWork = new char[nNumberOfBytesToRead * 2 + 4096 + 1]; //буфер Рабочий
    char* bufWork = notAlignBufWork + nNumberOfBytesToRead; //буфер
    if (size_t(bufWork) % 4096) { bufWork += 4096 - (size_t(bufWork) % 4096); }//адрес рабочего буфера тоже выровнял по размеру сектора/страницы  
    
    buf[nNumberOfBytesToRead] = '\0';//добавим нуль-терминатор
    bufWork[0] = '\0';//добавим нуль-терминатор
    bufWork[nNumberOfBytesToRead] = '\0';//добавим нуль-терминатор
 
    DWORD dwBytesReadWork = 0;
    DWORD findStatus = 0; //статус поиска
    bool errHandleEOF = false; //метка конца файла
    char* find;// указатель для поиска
    char* strStart;
    char* strEnd;
    char* bufWorkNew = bufWork;//буфер с учетом полной строки
    size_t strStartLen = 0;
    size_t strCount = 1; //счетчик строк
    std::string strOut; //итоговая строка
 
    _ULARGE_INTEGER ui; //Представляет 64-разрядное целое число без знака обединяя два 32-х разрядных
    ui.QuadPart = 0;
 
    OVERLAPPED  ovl;   // структура управления асинхронным доступом к файлу// инициализируем структуру OVERLAPPED
    ovl.Offset = 0;         // младшая часть смещения равна 0
    ovl.OffsetHigh = 0;      // старшая часть смещения равна 0
    ovl.hEvent = hEndRead;   // событие для оповещения завершения чтения
 
    // читаем данные из файла
 
    for (;;)
    {
        DWORD  dwBytesRead;
        DWORD  dwError;
        find = buf; //буфер
        // читаем одну запись
        if (!ReadFile(
            hFile,           // дескриптор файла
            buf,             // адрес буфера, куда читаем данные
            nNumberOfBytesToRead,// количество читаемых байтов
            &dwBytesRead,    // количество прочитанных байтов
            &ovl             // чтение асинхронное
        ))
        {
            switch (dwError = GetLastError())// решаем что делать с кодом ошибки
            {
            //эти ошибки смотрм после завершения асинхронной операции чтения, для возможности обработать рабочий буфер
            case ERROR_IO_PENDING: { break; }        // асинхронный ввод-вывод все еще происходит // сделаем кое-что пока он идет 
            case ERROR_HANDLE_EOF: { errHandleEOF = true;   break; } // мы достигли конца файла читалкой ReadFile
            default: {goto return1; }// другие ошибки
            }
        }
 
        //работаем асинхронно, выполняем код, пока ждем чтение с диска//
        bufWork[dwBytesReadWork] = '\0';//добавим нуль-терминатор
    goNextFind: //если ищем вторую и последующие строки в этом же буфере
        if (findStatus == 0)//goFind
        {
            find = strstr(bufWorkNew, findStr);
            if (find != NULL) //если нужная подстрока найдена
            {
                for (strStart = find; strStart >= bufWorkNew; strStart--)
                {
                    if (*strStart == '\n') { break; } //если нашли начало строки
                }
                strStart++; //не учитываем '\n'
 
                strEnd = strchr(find, '\n'); //ищем конец строки
                if (strEnd != NULL) //если нашли конец строки
                {
                    strOut = strOut + std::string(strStart, strEnd - strStart + 1);
                    if (!multiLine)
                    {
                        goto return0;
                    }
                    else//поиск в следующей строке начинаем с конца предыдущей
                    {
                        bufWorkNew = strEnd++;
                        findStatus = 0;
                        goto goNextFind;
                    }
                }
                else//если конец строки в следующем буфере или конец файла
                {
                    strOut = strOut + std::string(strStart);
                    findStatus = 1;
                }
            } //если нужная подстрока найдена
        }
        else if (findStatus == 1)//goBuf
        {
            strEnd = strchr(bufWork, '\n');
            if (strEnd != NULL) //если нашли конец строки
            {
                strOut = strOut + std::string(bufWork, strEnd - bufWork + 1);
                findStatus = 0;
                if (!multiLine)
                {
                    goto return0;
                }
                else//поиск в следующей строке начинаем с конца предыдущей
                {
                    bufWorkNew = strEnd++;
                    findStatus = 0;
                    goto goNextFind;
                }
            }
            else//если конец строки в следующем буфере или конец файла
            {
                strOut = strOut + std::string(bufWork);
            }
        }
 
        //блок дозагрузки рабочего буфера межбуферной строкой
        char* bufWorkEnd = bufWork + dwBytesReadWork; //конец буфера
        for (strStart = bufWorkEnd; strStart >= bufWork; strStart--) { if (*strStart == '\n') { break; } } //если нашли начало строки
        if (strStart < bufWork && ui.QuadPart>=nNumberOfBytesToRead) { goto return1; }; //если строка больше буфера (не найден разделитель), кроме первого буфера
        strStartLen = (bufWorkEnd - ++strStart); //размер буфера, который добавляем к рабочему
        //пишем начало строки в новый буфер
        bufWorkNew = buf - strStartLen;//bufWorkNew = bufWork - strStartLen;
        memcpy(bufWorkNew, strStart, strStartLen);
        //
 
        if (errHandleEOF) { goto return0; }
        //работаем асинхронно, выполняем код, пока ждем чтение с диска//
 
        // ждем, пока завершится асинхронная операция чтения
        WaitForSingleObject(hEndRead, INFINITE);
 
        // проверим результат работы асинхронного чтения // если возникла проблема ... 
        if (!GetOverlappedResult(hFile, &ovl, &dwBytesRead, FALSE))
        {
            switch (dwError = GetLastError())// решаем что делать с кодом ошибки
            {
            case ERROR_HANDLE_EOF:{ goto return0; break; }// мы достигли конца файла в ходе асинхронной операции
            default: {goto return1; }// другие ошибки
            }
        }
 
        //меняем буфер
        char* bufTmp = bufWork;
        bufWork = buf;
        buf = bufTmp;
        //
 
        // увеличиваем смещение в файле
        dwBytesReadWork = dwBytesRead;//кол-во считанных байт
        ui.QuadPart += nNumberOfBytesToRead; //добавляем смещение к указателю на файл
        ovl.Offset = ui.LowPart;// вносим смещение в младшее слово
        ovl.OffsetHigh = ui.HighPart;// вносим смещение в старшеее слово
    }
 
return0:
    CloseHandle(hFile);
    CloseHandle(hEndRead);
    delete[] notAlignBuf;
    delete[] notAlignBufWork;
    return strOut;
return1:
    CloseHandle(hFile);
    CloseHandle(hEndRead);
    delete[] notAlignBuf;
    delete[] notAlignBufWork;
    return "";
}
Миниатюры
Скорость чтения csv с разных носителей  
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
03.07.2020, 12:25

Программа для чтения csv
Нужно прочитать csv-файл, записать в массив и потом делать с ним всякие манипуляции и сортировки (ну это как раз самое простое). У меня...

Скорость импорта CSV
Здравствуйте. Прислали мне CSV-шник размером 10 гигов, чтобы сделать пару запросов. Поставил я себе MySQL Workbench, подготовил...

Bat - файл для чтения только одной строки из файла CSV
Добрый день! Подскажите пожалуйста как сделать батник чтобы он выводил только одну (2, 3, 4,...) строку из файла CSV. На текущий...

Как правильно написать скрипт для чтения файла с расширением .csv(Excel) ?
как правильно написать скрипт для чтения файла с расширением .csv(Excel) пишу вот такой програмный код: &lt;? $count = 1; $file =...

Скорость чтения/записи
Всем привет! Есть ли какие-нибудь библиотеки в Java, чтобы узнать скорость чтения/записи на диск? Интересует именно Java, потому что...


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

Или воспользуйтесь поиском по форуму:
149
Ответ Создать тему
Новые блоги и статьи
Часы электронные
Uhbif79 12.08.2026
Выкладываю программу часов. Программа позволяет: 1. Использовать системное время и дату, 2. Есть возможность вводить время и дату вручную. 3. Реализованы 2 будильника: начало и конец рабочего дня. . . .
Часы с будильником на основе класса QLCDNumber
Uhbif79 12.08.2026
Всем добрый день, выкладываю программу часов с будильником на основе класса QLCDNumber. Здесь я пробовал самостоятельно создавал классы, впервые столкнулся с видимостью переменной одного класса из. . .
Установка MinGW GCC 16.2 и CMake
8Observer8 10.08.2026
VK Видео: https:/ / vkvideo. ru/ video-240781534_456239017 YouTube: eY5-5PyI9NM Текстовая версия
Неделя из жизни имитационной модели склада: мои кривые руки растут, откуда надо
anaschu 10.08.2026
Неделя из жизни имитационной модели склада: как я почти написал неправильную логику и что с этим делать Работаю сейчас над учебно-рабочим проектом: строю в AnyLogic имитационную модель процессов. . .
Калькулятор для расчета родства
russiannick 07.08.2026
1. Задача: Создать калькулятор для расчета родства. Родственных связей существует 8 ступеней, такие как: p - отец P - мать q - муж Q - жена b - брат B - сестра s - сын S - дочь
Мир по моей воле
kumehtar 07.08.2026
Когда-то кажется, что всё просто. Ты весь такой светлый. Причиняешь добро. Борешься за справедливость в этом тёмном мире. Потом начинаешь замечать одну неприятную вещь. Почти каждый хороший. . .
Кредитный калькулятор
Maks 05.08.2026
Решение задачи по прикладной информатике средствами 1С. Задача: Напишите приложение-калькулятор, которое помогает рассчитывать параметры кредита для аннуитетного и дифференцированного видов. . .
У нас сейчас поговорку "Опять 25" нужно переделать на "Опять +35".
kumehtar 04.08.2026
С ностальгией вспоминаю времена моего детства, когда у нас и правда +25 - была максимальная температура летом. Раньше +25 °C реально казались вершиной жары, когда можно было весь день пропадать на. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru