据我所知,c ++有很好的表现。 Scala避风港。我写的是简单的任务。创建100 Mb阵列,在循环中初始化并将其写入磁盘10次。
Qt(5.3 clang)代码:
QTime myTimer;
myTimer.start();
int size = 100*1024*1024;
for (int i = 0;i <= 10;i++)
{
char *mem = new char[size];
for(int j = 0;j <= size - 1;j++)
mem[j] = j % 250;
for(int j = size - 1;j >= 0;j--)
mem[j] = j % 251;
QFile file("/tmp/" + QString::number(i) + ".dat");
file.open(QIODevice::WriteOnly);
file.write(mem, size);
file.flush();
file.close();
qDebug() << i;
}
// do something..
int nMilliseconds = myTimer.elapsed();
qDebug() << nMilliseconds;
Scala(2.11)代码:
var ms = System.currentTimeMillis
val size = 100*1024*1024
for (i <- 0 to 10){
val mem = new Array[Byte](size)
for(j <- 0 to size - 1)
mem(j) = (j % 250).asInstanceOf[Byte]
for(j <- size - 1 to 0)
mem(j) = (j % 251).asInstanceOf[Byte]
val file = new File("/tmp/" + i.toString + ".dat")
using(new FileOutputStream(file)){
stream =>
stream.write(mem)
stream.flush
}
println(i)
}
ms = System.currentTimeMillis - ms
println(ms)
MacBook Pro i7 8Gb 256 Gb SSD
Scala代码:5127毫秒
Qt代码:10408毫秒
为什么scala比c ++ qt快约2倍?
答案 0 :(得分:1)
正如我所怀疑的那样,你正在测量那些不存在的东西,或者更确切地说,不是你正在测量的东西。
要检查代码本身的开销是多少,您需要写入/dev/null
,并且需要对各个部分进行计时以查看真正需要时间的内容。对于下面的代码,这里是我得到的输出:
initialization took 2666 ms
buffered QFile writes to /dev/null took 0 ms
unbuffered QFile writes to /dev/null took 0 ms
fwrites to /dev/null took 5 ms
buffered temporary QFile writes took 115 ms
unbuffered temporary QFile writes took 102 ms
fwrites to temporary file took 118 ms
这是一致的。使用C库fwrite
实际上更慢比在此特定平台上使用QFile更慢。我的临时存储很快,BTW。
唉,这是在发布版本中。让我们看看它在调试构建中的外观:
initialization took 6524 ms
buffered QFile writes to /dev/null took 0 ms
unbuffered QFile writes to /dev/null took 0 ms
fwrites to /dev/null took 5 ms
buffered temporary QFile writes took 109 ms
unbuffered temporary QFile writes took 121 ms
fwrites to temporary file took 123 ms
您的减速。您测试了 debug 版本,它比您的硬件可以做的慢约2倍。 JVM在初始化的热路径上运行了JIT。这就是为什么Scala中的初始化与C ++完全一致,正如预期的那样。
这是OS X 10.9.4,Apple LLVM版本5.1(clang-503.0.40)(基于LLVM 3.4svn), 目标:x86_64-apple-darwin13.3.0,在3.7GHz第三代i7 CPU上使用Qt 5.3.1发布版本。
基准代码如下。由于QFile
是一个真正的C ++类并且正确实现了RAII,因此执行显式flush()
和close()
调用毫无意义。 C ++的重点在于你不必记住这种愚蠢。
#include <QElapsedTimer>
#include <QTemporaryFile>
#include <QByteArray>
#include <QFile>
#include <QTextStream>
#include <cstdio>
QTextStream out(stdout);
template <typename F> void time(const char * task, F fun)
{
QElapsedTimer timer;
timer.start();
int const N = 10;
for (int i = 0; i < N; ++i) fun();
out << task << " took " << timer.elapsed() << " ms" << endl;
}
QByteArray newData() {
const int size = 100*1024*1024;
QByteArray buf(size, Qt::Uninitialized);
// CoW isn't free, using mem takes ~1/3 less time than using buf[x].
char * const mem = buf.data();
for (int j = 0; j <= size - 1; j++)
mem[j] = j % 250;
for (int j = size - 1;j >= 0; j--)
mem[j] = j % 251;
return buf;
}
void qFileWrite(const QByteArray & data, const char * name,
QIODevice::OpenMode modeExtras = 0)
{
QFile f(QString::fromLocal8Bit(name));
if (! f.open(QIODevice::WriteOnly | modeExtras)) abort();
if (f.write(data) != data.size()) abort();
}
void cWrite(const QByteArray & data, const char * name)
{
std::FILE * f = fopen(name, "wb");
if (!f) abort();
if (fwrite(data.data(), 1, data.size(), f) != data.size()) abort();
if (fclose(f) == EOF) abort();
}
QByteArray tempFileName() {
QTemporaryFile f; f.setAutoRemove(false); if (!f.open()) abort();
return f.fileName().toLocal8Bit();
}
int main()
{
time("initialization", newData);
QByteArray const data = newData();
time("buffered QFile writes to /dev/null", [&]{
qFileWrite(data, "/dev/null");
});
time("unbuffered QFile writes to /dev/null", [&]{
qFileWrite(data, "/dev/null", QIODevice::Unbuffered);
});
time("fwrites to /dev/null", [&]{
cWrite(data, "/dev/null");
});
time("buffered temporary QFile writes", [&]{
qFileWrite(data, tempFileName());
});
time("unbuffered temporary QFile writes", [&]{
qFileWrite(data, tempFileName(), QIODevice::Unbuffered);
});
time("fwrites to temporary file", [&]{
cWrite(data, tempFileName());
});
return 0;
}