有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

C++ MMAP()与java MaPDyByTeffFor性能?

我已经从现有的java代码中开发C++项目。我有以下C++代码和java代码从同一个测试文件中读取,它由数百万个整数组成。p>

C++:

    int * arr = new int[len]; //len is larger than the largest int from the data
    fill_n(arr, len, -1);  //fill with -1
    long loadFromIndex = 0;
    struct stat sizeResults;
    long size;
    if (stat(fileSrc, &sizeResults) == 0) {
        size = sizeResults.st_size; //here size would be ~551950000 for 552M test file
    }
    mmapFile = (char *)mmap(NULL, size, PROT_READ, MAP_SHARED, fd, pageNum*pageSize);
    long offset = loadFromIndex % pageSize;
    while (offset < size) {
        int i = htonl(*((int *)(mmapFile + offset)));
        offset += sizeof(int);
        int j = htonl(*((int *)(mmapFile + offset)));
        offset += sizeof(int);
        swapElem(i, j, arr);
    }
    return arr;

爪哇:

    IntBuffer bb = srcFile.getChannel()
                    .map(MapMode.READ_ONLY, loadFromIndex, size)
                    .asIntBuffer().asReadOnlyBuffer();
    while (bb.hasRemaining()) {
        int i = bb.get();
        int j = bb.get();
        swapElem(i, j, arr); //arr is an int[] of the same size as the arr in C++ version, filled with -1
    }
    return arr;
C++和java中的p>^ {< CD1>}是相同的。它比较和修改数组中的值,但原始代码在这里发布有点长。出于测试目的,我将其替换为以下函数,这样循环就不会是死代码:

void swapElem(int i, int j, int * arr){   // int[] in Java
    arr[i] = j;
}
<>我假设C++版本应该优于java版本,但是测试给出了相反的结果——java代码比C++代码快两倍。有什么方法可以改进C++代码吗?

我觉得C++中的^ {CD2>}重复次数太多,所以对于{{CD3}},它是O(n)的加法,其中n是要读取的整数。对于Java的IntBuffer.get(),它只是直接读取缓冲区的索引,所以除了缓冲区索引的O(n)增量为1之外,不需要任何加法操作。因此,包括缓冲索引的增量,C++采用O(2n)的添加,而java需要O(n)的添加。当涉及到数以百万计的数据时,可能会导致显著的性能差异

遵循这个思想,我修改了C++代码如下:

    mmapBin = (char *)mmap(NULL, size, PROT_READ, MAP_SHARED, fd, pageNum*pageSize);
    int len = size - loadFromIndex % pageSize;
    char * offset = loadFromIndex % pageSize + mmapBin;
    int index = 0;
    while (index < len) {
        int i = htonl(*((int *)(offset)));
        offset += sizeof(int);
        int j = htonl(*((int *)(offset)));
        offset += sizeof(int);
        index+=2*sizeof(int);
    }

我以为会有轻微的性能提升,但事实并非如此

可以解释为什么C++代码比java代码慢吗?谢谢

更新:

我不得不道歉,当我说-O2不工作时,我这边出了问题。我把MaFILE文件弄乱了,所以C++代码没有使用-O2重新编译。我已经更新了性能,使用-O2的C++版本已经超过了java版本。这可以密封这个问题,但是如果有人想分享如何改进C++代码,我会遵循。一般来说,我希望它比Java代码快2倍,但目前不是这样。谢谢大家的意见

编译程序:g++

旗帜:-墙-c-氧气

Java版本:1.8.0_05

文件大小:552MB,所有4字节整数

处理器:2.53 GHz Intel Core 2 Duo

内存4GB 1067 MHz DDR3

更新的基准:

版本时间(毫秒)

C++:~1100

爪哇:~1400

C++(没有while循环):~35

Java(没有while循环):~40

在这些代码之前,我有一些东西会导致~35ms的性能(主要是用-1填充数组),但这在这里并不重要


共 (1) 个答案

  1. # 1 楼答案

    我对基准方法是否正确有些怀疑。这两种代码都是“死”代码。实际上,您并没有在任何地方使用i和j,因此gcc编译器或Java JIT可能会决定实际删除循环,因为它对未来的代码流没有影响

    <>无论如何,我会把C++代码改成:

    mmapFile = (char *)mmap(NULL, size, PROT_READ, MAP_SHARED, fd, pageNum*pageSize);
    long offset = loadFromIndex % pageSize;
    int i, j;
    int szInc = 2 * sizeof(int);
    while (offset < size) {
        scanf(mmapFile, "%d", &i);
        scanf(mmapFile, "%d", &j);
        offset += szInc; // offset += 8;
    }
    

    这相当于Java代码。此外,我将继续使用-O2作为编译标志。请记住htonl是一种额外的转换,而Java代码似乎没有这样做