Можно ли ускорить подсчет?
От: Аноним  
Дата: 24.07.05 08:30
Оценка:
У меня есть файл отчётов (~5 МБ), это простой текстовый файл, в котором содежжаться отчёты. Отчёты начинаются символом, с кодом 2 и заканчиваются символом с кодом 3. Написал простенький примерчик как подсчитать кол-во отчётов в этом файле:

#include <string>
#include <fstream>
#include <iostream>

enum {REP_BEGIN = 2, REP_END = 3};

int main()
{
    std::ifstream iFile("f:\\20050531");
    std::string str;

    long nRepCount = 0;
    bool bInRep = false;

    while(std::getline(iFile, str))
    {
        if(str[0] == REP_BEGIN)
        {
            bInRep = true;
            continue;
        }

        if((str[0] == REP_END) && (bInRep))
        {
            bInRep = false;
            ++nRepCount;
        }
    }

    std::cout << "Reports count: " << nRepCount << std::endl;

    return 0;
}

Так вот вопрос, можно ли как-нить ускорить процесс подсчёта, а то мой пример работает примерно сек 15-20?
Re: Можно ли ускорить подсчет?
От: Сергей  
Дата: 24.07.05 09:06
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Так вот вопрос, можно ли как-нить ускорить процесс подсчёта, а то мой пример работает примерно сек 15-20?


Я думаю, более эффективный способ — отображаемые на память файлы. Под виндой ищите информацию о CreateFileMapping/MapViewOfFile, под linux — mmap.
Re[2]: Можно ли ускорить подсчет?
От: Аноним  
Дата: 24.07.05 09:36
Оценка:
Здравствуйте, Сергей, Вы писали:

С>Здравствуйте, Аноним, Вы писали:


А>>Так вот вопрос, можно ли как-нить ускорить процесс подсчёта, а то мой пример работает примерно сек 15-20?


С>Я думаю, более эффективный способ — отображаемые на память файлы. Под виндой ищите информацию о CreateFileMapping/MapViewOfFile, под linux — mmap.


Попробовал, но сразу встал в ступор. Как загнать из памяти данные в мой вектор строк?

int FirstWay(std::string FileName)
{
    int nResult = -1;
    HANDLE hFile = INVALID_HANDLE_VALUE;
    HANDLE hFileMap = NULL;
    PVOID pvFile = NULL;

    __try
    {
        hFile = CreateFile(FileName.c_str(), GENERIC_WRITE|GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
        if(hFile == INVALID_HANDLE_VALUE)
        {
            std::cout << "File could not be opened." << std::endl;
            __leave;
        }

        DWORD dwFileSize = GetFileSize(hFile, NULL);
        hFileMap = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, dwFileSize + sizeof(char), NULL);        
        if(!hFileMap)
        {
            std::cout << "File map could not be opened." << std::endl;
            __leave;
        }
        
        pvFile = MapViewOfFile(hFileMap, FILE_MAP_WRITE, 0, 0, 0);        
        if(!pvFile)
        {
            std::cout << "Could not map view of file." << std::endl;
            __leave;
        }

        // !!!! Как загнать данные из pvFile в мой вектор????
        std::vector<std::string> MyVector;

    }
    __finally
    {
        if(pvFile)
        {
            UnmapViewOfFile(pvFile);
            pvFile = NULL;
        }

        if(hFileMap)
        {
            CloseHandle(hFileMap);
            hFileMap = NULL;
        }

        if(hFile != INVALID_HANDLE_VALUE)
        {
            CloseHandle(hFile);
            hFile = NULL;
        }
    }

    return nResult;
}
Re[3]: Можно ли ускорить подсчет?
От: ArtDenis Россия  
Дата: 24.07.05 11:13
Оценка:
Здравствуйте, <Аноним>, Вы писали:

С>>Я думаю, более эффективный способ — отображаемые на память файлы.

А>Попробовал, но сразу встал в ступор. Как загнать из памяти данные в мой вектор строк?

А зачем считывать данные из файла в вектор строк? Файл же проецируется в память. С памятью и работай. Можно написать свой класс, который будет при открытии сканировать файл и запоминать указатели на начала строк и длины строк. Для работы с содержимым файла (толко для чтения) можно предусмотреть функции типа
class MappedTextFile
{
...
    std::string get_string(size_t index);
    size_t size() const;
...
}
... << RSDN@Home 1.1.4 stable rev. 510>>
[ 🎯 Дартс-лига Уфы | 🌙 Программа для сложения астрофото ]
Re[4]: Можно ли ускорить подсчет?
От: Аноним  
Дата: 24.07.05 11:35
Оценка:
Здравствуйте, ArtDenis, Вы писали:

AD>Здравствуйте, <Аноним>, Вы писали:


С>>>Я думаю, более эффективный способ — отображаемые на память файлы.

А>>Попробовал, но сразу встал в ступор. Как загнать из памяти данные в мой вектор строк?

AD>А зачем считывать данные из файла в вектор строк? Файл же проецируется в память. С памятью и работай. Можно написать свой класс, который будет при открытии сканировать файл и запоминать указатели на начала строк и длины строк. Для работы с содержимым файла (толко для чтения) можно предусмотреть функции типа

AD>
AD>class MappedTextFile
AD>{
AD>...
AD>    std::string get_string(size_t index);
AD>    size_t size() const;
AD>...
AD>}    
AD>

Хорошо а как тогда эти методы реализовать, дело в том что я еще плохо разбираюсь в стл, а писать нужно с использованием оной библиотеки. Может каккой метод есть у std::string или алгоритм какой?
Re: Можно ли ускорить подсчет?
От: Анатолий Широков СССР  
Дата: 24.07.05 13:24
Оценка: +1
Поскольку файловый поток буферизируется, то врядли есть смысл толкать данные в строку, а уже после осуществлять ее анализ. Вообщем, попробуйте более экономичный вариант:

#include <algorithm>
#include <fstream>
#include <iostream>
#include <iterator>

int    main(int argc, char* argv[])
{
    if( argc < 2 )
        return 1;

    std::ifstream in(argv[1]);

    std::cout << std::count_if(
        std::istream_iterator<char>(in),
        std::istream_iterator<char>(),
        std::bind2nd(std::equal_to<char>(), char(3))
    );

    return 0;
}
Re: Можно ли ускорить подсчет?
От: MaximE Великобритания  
Дата: 24.07.05 13:27
Оценка:
On Sun, 24 Jul 2005 12:30:15 +0400, wrote:

> У меня есть файл отчётов (~5 МБ), это простой текстовый файл, в котором содежжаться отчёты. Отчёты начинаются символом, с кодом 2 и заканчиваются символом с кодом 3.


Если файл текстовый, то почему бы не представить отчет одной строкой?
Тогда в твоем распоряжении были бы все стандартные power tools, ориентированные на работу с текстовыми файлами: wc, grep, awk, ...

--
Maxim Yegorushkin
Posted via RSDN NNTP Server 1.9
Re[2]: Можно ли ускорить подсчет?
От: Анатолий Широков СССР  
Дата: 24.07.05 13:34
Оценка:
Небольшое дополнение — имеет смысл открывать файла как бинарный, поскольку представляют интерес только концевые маркеры — это еще больше повысит производительность, поскольку не будет тратится время на преобразование вида 0x0d0a -> '\n':

std::ifstream in(argv[1], std::ios::in | std::ios::binary );
Re: Можно ли ускорить подсчет?
От: alex-t  
Дата: 24.07.05 22:33
Оценка:
Здравствуйте, Аноним, Вы писали:

А>У меня есть файл отчётов (~5 МБ)...


Подсчет, конечно можно ускорить . Например, напишем такой цикл подсчета, вроде бы делающий то же самое и строго в рамках STL:

    for (std::istreambuf_iterator <char> p (iFile.rdbuf ()); p != std::istreambuf_iterator <char> (); ++p)
    {
        if(*p == REP_BEGIN)
        {
            bInRep = true;
            continue;
        }

        if((*p == REP_END) && (bInRep))
        {
            bInRep = false;
            ++nRepCount;
        }
    }


На файле 50 (!) МБ работает секунды 3 (Visual 7.1, release, Athlon 1700+). Согласен, что лучше открывать в бинарной моде, хотя разница оказалась невелика. Но очень советую перейти к проецированию в память, тут уже 50 МБ проскакивают незаметно, 250 за пару секунд, а дальше уже, видимо, тормозит, когда файл перестает влезать в оперативку...
Re[2]: Можно ли ускорить подсчет?
От: Аноним  
Дата: 25.07.05 07:52
Оценка:
Здравствуйте, alex-t, Вы писали:

AT>На файле 50 (!) МБ работает секунды 3 (Visual 7.1, release, Athlon 1700+). Согласен, что лучше открывать в бинарной моде, хотя разница оказалась невелика. Но очень советую перейти к проецированию в память, тут уже 50 МБ проскакивают незаметно, 250 за пару секунд, а дальше уже, видимо, тормозит, когда файл перестает влезать в оперативку...


Да действительно быстрее. Только снова появились вопросы.
1. Можно ли переделать этот цикл, так чтобы он работал со строками?
    for(std::istreambuf_iterator<char> p(iFile.rdbuf()); p != std::istreambuf_iterator<char>(); ++p)
    {
        if(*p == REP_BEGIN)
        {
            bInRep = true;
            continue;
        }
        if((*p == REP_END) && (bInRep))
        {
            bInRep = false;
            ++nRepCount;
        }
    }

Дело в том что мне нужно читать файл, потом выделять от туда один отчёт за другим и парсить их с помошью регспеков. Т.е. я хочу делать так. Если что-нить неправильно подправьте.
1. Открыть файл.
2. Считать первый отчёт в вектор строк и отправить в парсер.
3. Считать следующий отчёт в вектор строк и отправить в парсер.
и т.д...
Получилось нечно похожее на:

int ReadRepFile(std::string FileName)
{
    std::ifstream iFile(FileName.c_str());
    std::string str;
    std::vector<std::string> MyVector;

    long nRepCount = 0;        // Кол-во отчётов
    long nBadRepCount = 0;    // Кол-во "бытых" отчётов
    bool bInRep = false;

    while(std::getline(iFile, str))
    {
        if(str[0] == REP_BEGIN)
        {
            // Отчёт "битый", т.е. нет конца отчета (REP_END)
            // следовательно, парсить мы его не будем
            if(bInRep)
            {
                ++nBadRepCount;
                MyVector.clear();
            }

            // Находимся в процессе чтения отчёта
            bInRep = true;            
            continue;
        }

        // Дошли до конца отчёта, отправляем вектор строк с отчётом в парсер
        if((str[0] == REP_END))
        {
            if(bInRep)
            {
                bInRep = false;
                ++nRepCount;                
                ParseRep(MyVector);
                MyVector.clear();
            }
            else // Опять "битый" отчет - нет REP_BEGIN
            {
                ++nBadRepCount;
            }
        }

        if(bInRep)
        {
            // Добавляем строку отчёта в вектор
            MyVector.push_back(str);
        }

    }

    iFile.close();

    std::cout << "Reports count: " << nRepCount << std::endl;
    std::cout << "Bad reports count: " << nBadRepCount << std::endl;

    return nRepCount;
}

Как это оптимизировать по скорости?
Re[3]: Можно ли ускорить подсчет?
От: Аноним  
Дата: 25.07.05 08:39
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Как это оптимизировать по скорости?


С std::мишурой оптимизировать особо не получится
Re[4]: Можно ли ускорить подсчет?
От: Аноним  
Дата: 25.07.05 10:09
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, Аноним, Вы писали:


А>>Как это оптимизировать по скорости?


А>С std::мишурой оптимизировать особо не получится

Ну почему же тогда цикл:


    for(std::istreambuf_iterator<char> p(iFile.rdbuf()); p != std::istreambuf_iterator<char>(); ++p)
    {
        if(*p == REP_BEGIN)
        {
            bInRep = true;
            continue;
        }
        if((*p == REP_END) && (bInRep))
        {
            bInRep = false;
            ++nRepCount;
        }
    }

работает в 2 раза быстрее чем мой, просто я не знаю как этот цикл заточить под строки?
Re[5]: Можно ли ускорить подсчет?
От: Аноним  
Дата: 25.07.05 10:12
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, Аноним, Вы писали:


А>>Здравствуйте, Аноним, Вы писали:


А>>>Как это оптимизировать по скорости?


А>>С std::мишурой оптимизировать особо не получится

А>Ну почему же тогда цикл:

А>

А>    for(std::istreambuf_iterator<char> p(iFile.rdbuf()); p != std::istreambuf_iterator<char>(); ++p)
А>    {
А>        if(*p == REP_BEGIN)
А>        {
А>            bInRep = true;
А>            continue;
А>        }
А>        if((*p == REP_END) && (bInRep))
А>        {
А>            bInRep = false;
А>            ++nRepCount;
А>        }
А>    }
А>

А>работает в 2 раза быстрее чем мой, просто я не знаю как этот цикл заточить под строки?

Потому и быстрее, что строк там нет. А если не будет stream'ов, так ещё в 4 раза быстрее заработает.
Re[6]: Можно ли ускорить подсчет?
От: Аноним  
Дата: 25.07.05 11:43
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Потому и быстрее, что строк там нет. А если не будет stream'ов, так ещё в 4 раза быстрее заработает.

Что ж печально, ну ладно...
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.