我正在运行一些基准测试,以找到一种最有效的方法,用C ++编写一个巨大的数组(超过1Go的ASCII)。
所以我将std :: ofstream与fprintf进行了比较(参见我下面使用的开关)
case 0: {
std::ofstream out(title, std::ios::out | std::ios::trunc);
if (out) {
ok = true;
for (i=0; i<M; i++) {
for (j=0; j<N; j++) {
out<<A[i][j]<<" ";
}
out<<"\n";
}
out.close();
} else {
std::cout<<"Error with file : "<<title<<"\n";
}
break;
}
case 1: {
FILE *out = fopen(title.c_str(), "w");
if (out!=NULL) {
ok = true;
for (i=0; i<M; i++) {
for (j=0; j<N; j++) {
fprintf(out, "%d ", A[i][j]);
}
fprintf(out, "\n");
}
fclose(out);
} else {
std::cout<<"Error with file : "<<title<<"\n";
}
break;
}
我的问题是,与std :: ofstream相比,fprintf似乎要慢12倍。您是否知道我的代码中问题的根源是什么?或者,与fprintf相比,std :: ofstream是非常优化的?
(和另一个问题:你知道另一种更快的写文件方式)
非常感谢
(详细信息:我正在使用g ++ -Wall -O3进行编译)
答案 0 :(得分:17)
fprintf("%d"
需要运行时解析格式字符串,每个整数一次。每次编译时,编译器会解析ostream& operator<<(ostream&, int)
。
答案 1 :(得分:4)
好吧,fprintf()
必须在运行时做更多的工作,因为它必须解析和处理格式字符串。但是,考虑到输出文件的大小,我希望这些差异不会产生什么影响,并且会期望代码受I / O限制。
fsync()/sync()
会怎样?答案 2 :(得分:2)
ofstream中有一个文件缓冲区,这可能会减少访问磁盘的时间。另外,fprintf是一个带有可变参数的函数,它会调用一些va_#函数,但是不能调用。我认为你可以使用fwrite()或putc()进行测试。
答案 3 :(得分:1)
您是否已将sync_with_stdio设置在您显示的代码的上游某处?
虽然你所报告的内容与实证所见的相反,但大多数人都认为并相信你所看到的应该是常态。 iostream是类型安全的,而printf系列函数是可变函数,必须从格式说明符推断出va_list的类型。
答案 4 :(得分:1)
我在这里介绍一种使用unix函数打开,读取和写入在文本文件上写入整数的非常优化的方法。它们也可以在Windows上使用,只需给你一些可以使用的警告。 此实现仅适用于32位整数。
在您的包含文件中:
class FastIntegerWriter
{
private:
const int bufferSize;
int offset;
int file;
char* buffer;
public:
FastIntegerWriter(int bufferSize = 4096);
int Open(const char *filename);
void Close();
virtual ~FastIntegerWriter();
void Flush();
void Writeline(int value);
};
在源文件中
#ifdef _MSC_VER
# include <io.h>
# define open _open
# define write _write
# define read _read
# define close _close
#else
# include <unistd.h>
#endif
#include <fcntl.h>
FastIntegerWriter::FastIntegerWriter(int bufferSize) :
bufferSize(bufferSize),
buffer(new char[bufferSize]),
offset(0),
file(0)
{
}
int FastIntegerWriter::Open(const char* filename)
{
this->Close();
if (filename != NULL)
this->file = open(filename, O_WRONLY | O_CREAT | O_TRUNC);
return this->file;
}
void FastIntegerWriter::Close()
{
this->Flush();
if (this->file > 0)
{
close(this->file);
this->file = 0;
}
}
FastIntegerWriter::~FastIntegerWriter()
{
this->Close();
delete[] this->buffer;
}
void FastIntegerWriter::Flush()
{
if (this->offset != 0)
{
write(this->file, this->buffer, this->offset);
this->offset = 0;
}
}
void FastIntegerWriter::Writeline(int value)
{
if (this->offset >= this->bufferSize - 12)
{
this->Flush();
}
// Compute number of required digits
char* output = this->buffer + this->offset;
if (value < 0)
{
if (value == -2147483648)
{
// Special case, the minimum integer does not have a corresponding positive value.
// We use an hard coded string and copy it directly to the buffer.
// (Thanks to Eugene Ryabtsev for the suggestion).
static const char s[] = "-2147483648\n";
for (int i = 0; i < 12; ++i)
output[i] = s[i];
this->offset += 12;
return;
}
*output = '-';
++output;
++this->offset;
value = -value;
}
// Compute number of digits (log base 10(value) + 1)
int digits =
(value >= 1000000000) ? 10 : (value >= 100000000) ? 9 : (value >= 10000000) ? 8 :
(value >= 1000000) ? 7 : (value >= 100000) ? 6 : (value >= 10000) ? 5 :
(value >= 1000) ? 4 : (value >= 100) ? 3 : (value >= 10) ? 2 : 1;
// Convert number to string
output[digits] = '\n';
for (int i = digits - 1; i >= 0; --i)
{
output[i] = value % 10 + '0';
value /= 10;
}
this->offset += digits + 1;
}
我想这会比其他所有写入ascii文件的方法都要好:)你可以使用windows低级apis WriteFile和ReadFile获得更多性能,但它不值得付出努力。
使用它......
int main()
{
FastIntegerWriter fw;
fw.Open("test.txt");
for (int i = -2000; i < 1000000; ++i)
fw.Writeline(i);
return 0;
}
如果您未指定任何文件,则使用标准输出(控制台)。