>

~ 12.000.000 16 진수 줄과 1,6GB의 파일이 있습니다 파일 예 :

999CBA166262923D53D3EFA72F5C4E8EE1E1FF1E7E33C42D0CE8B73604034580F2
889CBA166262923D53D3EFA72F5C4E8EE1E1FF1E7E33C42D0CE8B73604034580F2

코드 예 :

vector<string>  buffer;
ifstream fe1("strings.txt");
string line1;
    while (getline(fe1, line1)) {
        buffer.push_back(line1);
    }

이제 로딩에는 약 20 분이 걸립니다. 속도를 높이는 방법에 대한 제안이 있으십니까? 미리 감사드립니다.


  • 답변 # 1

    큰 텍스트 파일을 std::vector<std::string> 에로드  각 std::string 에 힙 메모리를 할당하기 때문에 다소 비효율적이며 낭비입니다.  벡터를 여러 번 다시 할당합니다. 이러한 각 힙 할당에는 후드 아래의 힙 예약 유지 정보 (64 비트 시스템에서 일반적으로 할당 당 8 바이트)가 필요하며 각 라인에는 std::string 가 필요합니다.  이 방법으로로드 된 파일은 디스크보다 RAM에 더 많은 공간을 차지합니다.

    한가지 빠른 방법은 파일을 메모리에 매핑하고 반복자를 구현하여 그 안에있는 줄을 걷는 것입니다. 위에서 언급 한 문제를 회피합니다.

    작업 예 :

    #include <boost/interprocess/file_mapping.hpp>
    #include <boost/interprocess/mapped_region.hpp>
    #include <boost/iterator/iterator_facade.hpp>
    #include <boost/range/iterator_range_core.hpp>
    #include <iostream>
    class LineIterator
        : public boost::iterator_facade<
              LineIterator,
              boost::iterator_range<char const*>,
              boost::iterators::forward_traversal_tag,
              boost::iterator_range<char const*>
              >
    {
        char const *p_, *q_;
        boost::iterator_range<char const*> dereference() const { return {p_, this->next()}; }
        bool equal(LineIterator b) const { return p_ == b.p_; }
        void increment() { p_ = this->next(); }
        char const* next() const { auto p = std::find(p_, q_, '\n'); return p + (p != q_); }
        friend class boost::iterator_core_access;
    public:
        LineIterator(char const* begin, char const* end) : p_(begin), q_(end) {}
    };
    inline boost::iterator_range<LineIterator> crange(boost::interprocess::mapped_region const& r) {
        auto p = static_cast<char const*>(r.get_address());
        auto q = p + r.get_size();
        return {LineIterator{p, q}, LineIterator{q, q}};
    }
    inline std::ostream& operator<<(std::ostream& s, boost::iterator_range<char const*> const& line) {
        return s.write(line.begin(), line.size());
    }
    int main() {
        boost::interprocess::file_mapping file("/usr/include/gnu-versions.h", boost::interprocess::read_only);
        boost::interprocess::mapped_region memory(file, boost::interprocess::read_only);
        unsigned n = 0;
        for(auto line : crange(memory))
            std::cout << n++ << ' ' << line;
    }
    
    

  • 답변 # 2

    전체 파일을 메모리로 읽을 수 있습니다. C ++ 스트림으로 수행하거나 메모리 매핑 파일 또는 자체 파일 읽기 API와 같은 플랫폼 별 API를 사용하여 더 많은 성능을 얻을 수 있습니다.

    이 데이터 블록이 있으면 성능을 위해 더 이상 복사를 피하고 대신 사용하려고합니다. C ++ 17에서는 std::string_view 가 있습니다.  이것은 std::string 와 유사합니다  그러나 기존 문자열 데이터를 사용하여 사본을 피합니다. 그렇지 않으면 C 스타일 char* 로 작업 할 수 있습니다.  개행을 널 ( \0 )로 대체하여 문자열 ), 포인터 쌍 (시작/끝) 또는 포인터와 크기를 사용합니다.

    여기서 나는 string_view 를 사용했다 또한 줄 바꿈이 항상 \n 라고 가정했습니다.  끝에 줄 바꿈이 있습니다. 그렇지 않은 경우 루프를 조정해야 할 수도 있습니다. vector 의 크기를 추측  또한 약간의 성능을 얻을 수 있으므로 파일 길이에서 그렇게 할 수 있습니다. 오류 처리도 생략했습니다.

    std::fstream is("data.txt", std::ios::in | std::ios::binary);
    is.seekg(0, std::ios::end);
    size_t data_size = is.tellg();
    is.seekg(0, std::ios::beg);
    std::unique_ptr<char[]> data(new char[data_size]);
    is.read(data.get(), data_size);
    
    std::vector<std::string_view> strings;
    strings.reserve(data_size / 40); // If you have some idea, avoid re-allocations as general practice with vector etc.
    for (size_t i = 0, start = 0; i < data_size; ++i)
    {
        if (data[i] == '\n') // End of line, got string
        {
            strings.emplace_back(data.get() + start, i - start);
            start = i + 1;
        }
    }
    
    

    더 나은 성능을 얻으려면 루프를 실행하여 파일 IO와 병렬로 CPU 작업을 수행 할 수 있습니다. 스레드 또는 플랫폼 별 비동기 파일 IO를 사용하여 수행 할 수 있습니다. 그러나이 경우 루프가 매우 빠르므로 얻을 것이 많지 않습니다.

  • 답변 # 3

    충분한 RAM 메모리를 할당하고 거의 한 번에 전체 텍스트 파일을 읽을 수 있습니다. 메모리 포인터로 RAM의 데이터에 액세스 할 수있는 것보다. 약 3 초 안에 전체 4GB 텍스트 파일을 읽었습니다.

  • 이전 javascript - 사용자 정의 양식 필드의 Z- 색인 문제 (선택)
  • 다음 이 코드는 자동 테스트에서 테스트에 실패했지만 레일 콘솔에서 작동합니다