我使用下面的方法来读取大空格分隔的txt文件(大约900 Mb)。我花了879s将数据加载到内存中。我想知道是否有更有效的方法来读取txt文件?
另一个相关问题是:使用2D矢量存储这么大的数据集是个好主意吗?
这是我的代码
void Grid::loadGrid(const char* filePathGrid)
{
// 2D vector to contain the matrix
vector<vector<float>> data;
unsigned nrows, ncols;
double xllcorner, yllcorner;
int cellsize, nodataValue;
const int nRowHeader = 6;
string line, strtmp;
ifstream DEMFile;
DEMFile.open(filePathGrid);
if (DEMFile.is_open())
{
// read the header (6 lines)
for (int index = 0; index < nRowHeader; index++)
{
getline(DEMFile, line);
istringstream ss(line);
switch (index)
{
case 0:
while (ss >> strtmp)
{
istringstream(strtmp) >> ncols;
}
break;
case 1:
while (ss >> strtmp)
{
istringstream(strtmp) >> nrows;
}
break;
case 2:
while (ss >> strtmp)
{
istringstream(strtmp) >> xllcorner;
}
break;
case 3:
while (ss >> strtmp)
{
istringstream(strtmp) >> yllcorner;
}
break;
case 4:
while (ss >> strtmp)
{
istringstream(strtmp) >> cellsize;
}
break;
case 5:
while (ss >> strtmp)
{
istringstream(strtmp) >> nodataValue;
}
break;
}
}
// Read in the elevation values
if (ncols * nrows > 0)
{
// Set up sizes. (rows x cols)
data.resize(nrows);
for (unsigned row = 0; row < nrows; ++row)
{
data[row].resize(ncols);
}
// Load values in
unsigned row = 0;
while (row < nrows)
{
getline(DEMFile, line);
istringstream ss(line);
for (unsigned col =0; col < ncols; col++)
{
ss >> data[row][col];
}
row ++;
}
DEMFile.close();
}
}
else cout << "Unable to open file";
}
答案 0 :(得分:3)
关于你的第二个问题:
我会选择使用一维向量,然后将其索引(row * ncols + col)。
这至少会减少内存消耗,但也可能对速度产生重大影响。
我不记得“矢量向量”是否是标准所认可的成语,但如果没有对“向量”的特殊处理,则存在过多的复制和内存重新分配的风险。矢量案例。
答案 1 :(得分:3)
与其他问题相比,答案并不多(这些问题不适合评论)。
观察:我认为如果不了解更多有关优化潜力的内容,很难回答矢量或其他更好的内存存储问题......一些与数据相关的问题就在那里。
您是否可以修改时序逻辑以读取标题值,然后计算以下方案:
1) Read-only, just pull each line into memory. Disable the the grid
parsing & assignment part. Goal to benchmark raw reads on file.
Also no "resize" operations on your "data" member.
2) Memory allocation (just read the headers and "resize" the "data" member;
don't loop through remainder of file).
3) Everything (code as-posted).
对我来说,读取1gb以下大小的文件将被操作系统缓存。
所以...
我鼓励你运行5次以上,看看后续运行是否一致。 (如果你没有检查它,看起来你可能会从一个小的改动到代码获得一个很大的加速,但实际上只是因为数据文件是由操作系统缓存而你的&#34;收益&# 34;随着下次重启而蒸发。
换句话说,数据文件看起来像是网格中每个值的完整转储。
示例:除了6&#34;标题&#34;线条,100 x 200&#34;网格&#34;文件中将有100行,每行有200行。所以6 + 100 * 200 = 20,006行。
你提到了一个900 MB的数据文件。
我会做一些假设,只是为了它的乐趣。
如果您的值格式一致(例如&#34; 0.000000&#34; thru&#34; 1.000000&#34;),则表示每个值有8个字符。
假设简单的编码(每个字符1个字节),那么你就可以在900 MB中使用10,000 ^ 2网格。
忽略标题&#34; line&#34;和行尾delims(只会出现舍入错误):
1kb有1,024个字符
1mb有1,048,576个字符(1024 ^ 2)
▲900mb有943,718,400个字符(1024 ^ 2 * 900)
8个char元素值产生117,964,800个元素(1024 ^ 2 * 900/8)
大约是10,000 ^ 2网格(10,861来自sqrt(1024 ^ 2 * 900/8))。
这是否是中等接近,尺寸方面的?
您想要支持的最大数字网格元素是多少?百万?十亿?更多?
看起来像任何这样的&#34;限制&#34;将由产生数据文件的任何东西驱动。
你在你的价值观中看到了什么样的分布?
你在价值观中看到了什么样的范围?
值是否始终为0.0000 - 1.0000?或者C ++浮点数的任何有效值?
你能产生价值的频率分布吗?
例如
计算下次构建Grid时Grid中有多少个不同的值?
这可能有助于找到您可以尝试优化的任何值?
也许许多网格元素是零,或1,或......?
如果是这样的话,你可能会考虑一种带有接口的稀疏矩阵方法,这种接口会给呼叫者带来错觉
完全实例化的网格(例如,不需要分配空间)。
我不知道&#34;稀疏矩阵&#34;的收支平衡点是什么?开始付清的方法。
(除非我对至少30%的网格元素有一个共同的值,否则我不会考虑。)
如果你正在操纵&#34; raw&#34;风格的图像,价值可能会到处都是。
如果你的价值观有一个模式,也许你可以利用它。
我想这将是一种数据压缩。
你能计算一个中点值并只存储偏移吗?
可以从网格坐标计算出值吗? (我猜不会)。
另一条评论(@MaruisBancila)提到二进制格式与字符格式。
很有道理。
从8个字符到4个字节的浮点数会将文件大小减半。
填充网格后,&#34;用户&#34;做到了吗?
他们是在运营整个电网吗?
只是它的一部分?
你可以&#34;窗口&#34;在您的数据上使消费者满意并且只将一部分网格值加载到内存中?
(我猜不会,但从来没有伤害过要求)。
好的,这就是我能想到的所有问题。
答案 2 :(得分:2)
很棒的答案。使用二进制格式而不是纯文本会给我带来很好的性能提升。
我也有人发给我这个代码。我会玩更多的东西,拿出一个V2。
#include <fstream>
#include <iomanip>
#include <iostream>
#include <iterator>
#include <sstream>
#include <string>
#include <deque>
#include <vector>
using namespace std;
/* ////////////////////////////////////////////////////////////////////////////
timer stuff
//////////////////////////////////////////////////////////////////////////// */
//----------------------------------------------------------------------------
typedef double epoch_time_t;
//----------------------------------------------------------------------------
#ifdef __WIN32__
#include <windows.h>
epoch_time_t get_epoch_time() // Since 1601 Jan 1
{
FILETIME f;
GetSystemTimeAsFileTime( &f );
LARGE_INTEGER t =
{ {
f.dwLowDateTime,
f.dwHighDateTime
} };
return t.QuadPart / 10000000.0; // 100 nano-second intervals
}
void waitforkeypress()
{
WaitForSingleObject(
GetStdHandle( STD_INPUT_HANDLE ),
INFINITE
);
}
//----------------------------------------------------------------------------
#else // POSIX
#include <sys/time.h>
epoch_time_t get_epoch_time() // Since 1970 Jan 1
{
struct timeval tv;
if (gettimeofday( &tv, NULL )) return 0.0;
return tv.tv_sec + tv.tv_usec / 1000000.0;
}
#include <unistd.h>
#include <termios.h>
#include <poll.h>
#define INFINITE (-1)
void waitforkeypress()
{
struct termios initial_settings;
tcgetattr( STDIN_FILENO, &initial_settings );
struct termios settings = initial_settings;
settings.c_lflag &= ~(ICANON);
tcsetattr( STDIN_FILENO, TCSANOW, &settings );
struct pollfd pls[ 1 ];
pls[ 0 ].fd = STDIN_FILENO;
pls[ 0 ].events = POLLIN | POLLPRI;
poll( pls, 1, INFINITE );
tcsetattr( STDIN_FILENO, TCSANOW, &initial_settings );
}
#endif
//----------------------------------------------------------------------------
ostream& print_epoch_time( ostream& outs, epoch_time_t elapsed_time )
{
unsigned minutes = (unsigned) elapsed_time / 60;
unsigned seconds = (unsigned) elapsed_time % 60;
unsigned hundredths = (unsigned)(elapsed_time * 100) % 100;
outs << "It took you "
<< setfill( '0' ) << minutes << ":"
<< setw( 2 ) << seconds << "."
<< setw( 2 ) << hundredths << endl;
return outs;
}
/* ////////////////////////////////////////////////////////////////////////////
loading stuff
//////////////////////////////////////////////////////////////////////////// */
typedef vector <float> container;
typedef deque <container> container2;
//----------------------------------------------------------------------------
void load_at_once( const char* filename, string& result )
{
ifstream f( filename, ios::binary );
result.assign( istream_iterator <char> ( f ), istream_iterator <char> () );
}
//----------------------------------------------------------------------------
struct data_t
{
unsigned nrows;
unsigned ncols;
double xllcorner;
double yllcorner;
int cellsize;
double nodatavalue;
container2 data;
};
void load_in_pieces( istream& f, data_t& data )
{
string s;
f >> s >> data.ncols
>> s >> data.nrows
>> s >> data.xllcorner
>> s >> data.yllcorner
>> s >> data.cellsize
>> s >> data.nodatavalue;
data.data.resize( data.nrows );
for (container2::iterator row = data.data.begin(); row != data.data.end(); ++row)
{
row->resize( data.ncols );
for (container::iterator col = row->begin(); col != row->end(); ++col)
{
f >> *col;
}
}
}
//----------------------------------------------------------------------------
int main()
{
epoch_time_t start, stop;
string raw_data;
data_t data;
cout << "Please wait while loading...\n";
start = get_epoch_time();
load_at_once( "data.txt", raw_data );
istringstream iss( raw_data );
load_in_pieces( iss, data );
stop = get_epoch_time();
print_epoch_time( cout, stop - start );
return 0;
}