加快使用c ++将大文件写入磁盘的速度

问题描述 投票:0回答:2

我需要将一个较大的csv文件写入磁盘。我已将问题简化为以下代码。当我在Windows 7机器上运行VS 2017进行编译时,平均运行时间为26秒。有人可以建议一种无需更改数据容器或输出格式即可加快速度的方法吗?任何帮助将不胜感激。

PS:可能很明显,但是加速应该是硬件上的基本情况

我尝试使用fopen和fprintf,但结果较差。我还尝试设置缓冲区大小,但没有成功。

#include <iostream>
#include <iomanip>
#include <fstream> 
#include <chrono>
#include <vector>
#include <string>

typedef std::chrono::high_resolution_clock Clock;
typedef std::vector<double> VecD;
typedef std::vector<VecD> VecVecD;

void test_file_write_stream() {
    VecVecD v(10000, VecD(2000, 1.23456789));
    const std::string delimiter(",");
    const std::string file_path("c:\\junk\\speedtest.csv");
    auto t1_stream = Clock::now();
    std::ofstream ostream(file_path.c_str());
    if (!ostream.good())
        return;
    ostream << std::setprecision(12);

    for (const auto & row : v) {
        for (const auto & col : row) {
            ostream << col << delimiter;
        }
        ostream << std::endl;
    }
    auto t2_stream = Clock::now();
    std::cout << "Stream test: " << std::chrono::duration_cast<std::chrono::microseconds>(t2_stream - t1_stream).count() / 1.0e6 << " seconds" << std::endl;
}

void main(int argc, char * argv[]) {
    test_file_write_stream();
}

流测试:26.2086秒

c++ performance io outputstream
2个回答
0
投票

我在没有完全分配任何大块内存,向量或迭代器的情况下,针对完全相同的基准运行了此代码。只是

double value = 1.23456789;
for (int r = 0; r < rows; ++r) {
    for (int c = 0; c < cols; ++c) {
        ostream << value << delimiter;
    }
    ostream << std::endl;
}

两者是一致的。问题的明显事实是,写入磁盘需要时间,而向磁盘写入那么多时间则需要花费很多时间。您尚未表现出任何不健康的增长方式,因此这里没有问题可以解决。


0
投票

我尝试了您的代码,并做了一些次要的臀部优化-但是得到了一致的结果。对我而言,基线约为14 s,并且一直保持接近该水平。做得好-O3

我用一维版本替换了您的std::vector<std::vector<double>>,并且只做了很小的改进就将它std::copy放到了磁盘上。

[仅当我放弃并将内存原样(not作为.csv)转储到磁盘时,我才降到1-3秒。

最大的缺点是,我转储的东西不能以任何方式移植。希望它可以在美好的一天读回到同一台计算机上,但是我不建议您以这种方式将double转储为真实的:

#include <chrono>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <iterator>
#include <string>
#include <vector>

typedef std::chrono::high_resolution_clock Clock;

// custom 2D array with a 1D memory layout
template<typename T>
class array2d {
public:
    array2d(size_t h, size_t w, const T& value = T{}) : data_(h * w, value), w_(w) {}

    inline double* operator[](size_t y) { return &data_[y * w_]; }
    inline double const* operator[](size_t y) const { return &data_[y * w_]; }

    inline size_t width() const { return w_; }

    T const* data() const { return data_.data(); }
    size_t size() const { return data_.size(); }

private:
    std::vector<double> data_;
    size_t w_;
};

using VecVecD = array2d<double>;

void test_file_write_stream() {
    VecVecD v(10000, 2000, 1.23456789);

    const std::string delimiter(",");
    const std::string file_path("c:\\junk\\speedtest.csv");

    auto t1_stream = Clock::now();

    std::ofstream ostream(file_path.c_str(), std::ios::binary);
    if(!ostream) return;

    ostream << std::setprecision(12);

    /* this may give a somewhat better performance than yours, but not much:

    std::copy(v.data(), v.data() + v.size(),
              std::ostream_iterator<double>(ostream, delimiter));
    */

    // non-portable binary dump
    ostream.write(reinterpret_cast<const char*>(v.data()),
                  static_cast<std::streamsize>(v.size() * sizeof(double)));

    auto t2_stream = Clock::now();

    auto elapsed_s =
        std::chrono::duration_cast<std::chrono::seconds>(t2_stream - t1_stream);
    std::cout << "Stream test: " << elapsed_s.count() << " seconds" << std::endl;
}

int main(int, char**) {
    test_file_write_stream();
}
© www.soinside.com 2019 - 2024. All rights reserved.