1

Java のこのコードが C++ よりも速いのはなぜですか? 2 つのファイルをバイト単位で比較する必要があります。たとえば、2 つのファイル サイズを比較すると、650mb は C++ で 40 秒、Java で 10 秒かかります。

C++ コード:

//bufferSize = 8mb
std::ifstream lFile(lFilePath.c_str(), std::ios::in | std::ios::binary);
std::ifstream rFile(rFilePath.c_str(), std::ios::in | std::ios::binary);

std::streamsize lReadBytesCount = 0;
std::streamsize rReadBytesCount = 0;

do {
    lFile.read(p_lBuffer, *bufferSize);
    rFile.read(p_rBuffer, *bufferSize);
    lReadBytesCount = lFile.gcount();
    rReadBytesCount = rFile.gcount();

    if (lReadBytesCount != rReadBytesCount ||
        std::memcmp(p_lBuffer, p_rBuffer, lReadBytesCount) != 0)
    {
        return false;
    }
} while (lFile.good() || rFile.good());

return true;

そして Java コード:

InputStream is1 = new BufferedInputStream(new FileInputStream(f1)); 
InputStream is2 = new BufferedInputStream(new FileInputStream(f2)); 

byte[] buffer1 = new byte[64];
byte[] buffer2 = new byte[64];

int readBytesCount1 = 0, readBytesCount2 = 0;

while (
    (readBytesCount1 = is1.read(buffer1)) != -1 &&
    (readBytesCount2 = is2.read(buffer2)) != -1
) {             
    if (Arrays.equals(buffer1, buffer2) && readBytesCount1 == readBytesCount2)
        countItr++;
    else {
        result = false
        break;
    }
}
4

3 に答える 3

10

考えられる答えの 1 つは、Java バージョンが 64 バイトを使用しているのに対し、C++ コードは 8 Mb のバッファーを使用しているということです。違いが最初の数バイト以内の場合はどうなりますか? その場合、Java バージョンは違いを見つけるために 64 バイトを読み取るだけで済みますが、C++ バージョンは 800 万バイトを読み取る必要があります。それらを比較したい場合は、実際には同じバッファーサイズを使用する必要があります。

さらに、ファイルが同一である場合、違いには他の理由が考えられます。8 MB のデータを割り当てるのにかかる時間 (これは複数のページにまたがることもあります) と、単純に 64 バイトを割り当てるのにかかる時間を考えてみてください。シーケンシャルに読み取っているため、オーバーヘッドは実際にはメモリ側にあります。

于 2013-03-02T17:23:38.550 に答える
1

私はちょうどあなたのJavaプログラムを取り、同等のC++プログラムを書きました.2つの同一のファイルを比較するのに、どちらもほぼ同じ時間がかかります.

考えられる簡単な説明の 1 つは、最初に C++ プログラムを実行し、次に Java プログラムを実行したことです。これが唯一のテストである場合、実行時間の違いはキャッシングだけで説明できますが、今日のハードウェアで 650 MB を読み取るのに 40 秒はかなりの時間です。

データ ブロックはシステム ファイル キャッシュにあり、2 回目はファイルを取得するためのディスク アクセスがありませんでした。同等の結果を得るには、C++ と Java プログラムでテストを複数回実行します。

あなたのコードでは、

lFile.read(p_lBuffer, *bufferSize);

冒頭のあなたのコメントと矛盾しています

//bufferSize = 8mb

したがって、実際の完全なコードを表示しない限り、誰の推測も有効です。

自分のドッグフードを食べるために

#include <iostream>
#include <fstream>
#include <cstring>

const size_t N = 8 * 1024 * 1024;
char buf1[N], buf2[N];

int main(int argc, char **argv)
{
    std::iostream::sync_with_stdio(false);
    std::ifstream f1(argv[1]);
    std::ifstream f2(argv[2]);
    while (f1.read(buf1, sizeof(buf1)) && f2.read(buf2, sizeof(buf2))) {
        size_t n1 = f1.gcount(), n2 = f2.gcount();
        if (n1 != n2 || memcmp(buf1, buf2, n1) != 0)
            return 1;
    }

    return 0;
}
于 2013-03-02T17:45:40.273 に答える
0

バッファサイズの答えは本当に良いものであり、おそらく非常に重要ですが、問題の別の原因として考えられるのは、iostreamライブラリの使用です。私は通常、この種の作業にはそのライブラリを使用しません。これが引き起こす可能性のある問題の 1 つは、たとえば、バッファリングによる余分なコピーiostreamです。rawreadwritecalls を使用します。

たとえば、Linux C++11 プラットフォームでは、次のようにします。

#include <array>
#include <algorithm>
#include <string>
#include <stdexcept>

// Needed for open and close on a Linux platform
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

using ::std::string;

bool same_contents(const string &fname1, const string &fname2)
{
   int fd1 = ::open(fname1.c_str(), O_RDONLY);
   if (fd1 < 0) {
      throw ::std::runtime_error("Open of " + fname1 + " failed.");
   }
   int fd2 = ::open(fname2.c_str(), O_RDONLY);
   if (fd2 < 0) {
      ::close(fd1);
      fd1 = -1;
      throw ::std::runtime_error("Open of " + fname2 + " failed.");
   }

   bool same = true;
   try {
      ::std::array<char, 4096> buf1;
      ::std::array<char, 4096> buf2;
      bool done = false;

      while (!done) {
         int read1 = ::read(fd1, buf1.data(), buf1.size());
         if (read1 < 0) {
            throw ::std::runtime_error("Error reading " + fname1);
         }
         int read2 = ::read(fd2, buf2.data(), buf2.size());
         if (read2 < 0) {
            throw ::std::runtime_error("Error reading " + fname2);
         }
         if (read1 != read2) {
            same = false;
            done = true;
         }
         if (same && read1 > 0) {
            const auto compare_result = ::std::mismatch(buf1.begin(),
                                                        buf1.begin() + read1,
                                                        buf2.begin());
            if (compare_result.first != (buf1.begin() + read1)) {
               same = false;
            }
         }
         if (!same || (buf1.size() > read1)) {
            done = true;
         }
      }
   } catch (...) {
      if (fd1 >= 0) ::close(fd1);
      if (fd2 >= 0) ::close(fd2);
      throw;
   }
   if (fd1 >= 0) ::close(fd1);
   if (fd2 >= 0) ::close(fd2);
   return same;
}
于 2013-03-02T17:30:19.850 に答える