为什么我的测试scala 2.11比c ++ qt 5.3更快?

时间:2014-08-07 19:32:27

标签: c++ qt scala

据我所知,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倍?

1 个答案:

答案 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;
}