【发布时间】:2021-12-29 05:42:12
【问题描述】:
我在 CSV 文件中有一百万个条目,需要加载它。但是,完成加载大约需要 2 分钟。我需要解决这个问题以使数据加载更快。有没有更好的方法可以解决?所以我可以研究并尝试修复它。感谢您的帮助。
CSVReader.h
#pragma once
#include "OrderBookEntry.h"
#include <vector>
#include <string>
class CSVReader
{
public:
CSVReader();
static std::vector<OrderBookEntry> readCSV (std::string csvFile);
};
CSVReader.cpp
#include "CSVReader.h"
#include <iostream>
#include <fstream>
CSVReader::CSVReader() {
}
std::vector<OrderBookEntry> CSVReader::readCSV(std::string csvFilename) {
std::vector<OrderBookEntry> entries;
std::ifstream csvFile{csvFilename};
std::string line;
if (csvFile.is_open())
{
while (std::getline(csvFile, line))
{
try {
OrderBookEntry obe = stringsToOBE(tokenise(line, ','));
entries.push_back(obe);
}
catch(const std::exception& e){
std::cout << "CSVReader::readCSV bad data" << std::endl;
}
}//end of while
}
std::cout << "Successfully read " << entries.size() << " entries" << std::endl;
return entries;
}
std::vector<std::string> CSVReader::tokenise(std::string csvLine, char separator) {
std::vector<std::string>tokens;
signed int start, end;
std::string token;
start = csvLine.find_first_not_of(separator, 0);
do {
end = csvLine.find_first_of(separator, start);
if (start == csvLine.length() || start == end) break;
if (end >= 0) token = csvLine.substr(start, end - start);
else token = csvLine.substr(start, csvLine.length() - start);
tokens.push_back(token);
start = end + 1;
} while (end > 0);
return tokens;
}
OrderBookEntry CSVReader::stringsToOBE(std::vector<std::string>tokens) {
double price, amount;
if (tokens.size() != 5) {
std::cout << "Bad Input" << std::endl;
throw std::exception{};
}
try {
//we have 5 tokens
price = std::stod(tokens[3]);
amount = std::stod(tokens[4]);
}
catch(const std::exception& e){
std::cout << "Bad Float!" << tokens[3] << std::endl;
std::cout << "Bad Float!" << tokens[4] << std::endl;
throw;
}
OrderBookEntry
obe{price,amount,tokens[0],tokens[1],OrderBookEntry::stringToOrderBookType(tokens[2])};
return obe;
}
【问题讨论】:
-
您需要一次将所有条目加载到主内存中吗? “一百万个条目”听起来您应该使用数据库,而不是电子表格。
-
了解如何将变量作为引用传递给函数,而不是在它们很大时复制它们。
stringsToOBE应该是stringsToOBE(const std::vector<string>& tokens)。 -
1.重新考虑程序的架构。 2. 将复制成本高昂的变量作为 const 引用传递。
-
1.你写的并不理想,但在现代机器上它应该更快。也许你可以提供一个测试文件。 2. 确保在发布配置中测试您的程序。 Debug 和 Release 配置之间的差异可能很大。 3.你没看懂
throw/catch. 4.strtod`不扔。` -
如果您知道文件的确切大小以及 std::vector 的大小,据我了解,最有效的方法是在您的 std::vector 上使用保留。因此,如果您有 1,000,000 行“条目”,请执行 entries.reserve(1000000);预分配内存。根据我的经验,这比使用 std::vector.push_back(); 更快。因为 push_back() 必须添加内存 1,000,000 次,而不是使用 reserve() 一次完成所有操作。您还需要一个虚拟计数器,以便每次读取一行并向其中添加数据时都可以通过向量进行索引。
标签: c++ performance csv