【问题标题】:C and C++ weird performance differenceC 和 C++ 奇怪的性能差异
【发布时间】:2015-05-18 15:23:21
【问题描述】:

在阅读我的帖子之前,请考虑到我是 C 和 C++ 的新手。 我主要是一名托管代码开发人员。

我有两段相同的代码(至少我是这么认为的)。 一个在 C 中,一个在 C++ 中。 该代码基本上检查数字是否为质数,如果是,则将其存储在容器中。

C++

Main.cpp

#include <iostream>
#include <vector>
#include <time.h>

static bool isPrime(const int& number) {

    if((number & 1) == 0) {
        if(number == 2)
            return true;
        else
            return false;
    }

    for(int i = 3; (i * i) <= number; i++) {

        if((number % i) == 0)
            return false;
    }

    return number != 1;
}

int main(int argc, const char * argv[]) {

    std::vector<int> vector;
    clock_t start = clock();
    for(int i = 0; i < 30000000; i++) {

        if(isPrime(i))
            vector.push_back(i);
    }
    clock_t end = clock();
    clock_t seconds = (end - start) / CLOCKS_PER_SEC;
    std::cout << "done after " << seconds << " seconds " << std::endl;

    return 0;
}

C

矢量.c

#include <stdlib.h>


typedef struct vector_class {
    void(*push_back)(struct vector_class *vector_instance, const int *data);
    int *data;
    int length;
    int capacity;
} vector;

static void push_back(vector *vector_instance, const int *data) {

    if(vector_instance->length >= vector_instance->capacity) {

        vector_instance->capacity *= 2;
        vector_instance->data = (int*) realloc(vector_instance->data, sizeof(int) * vector_instance->capacity);
    }
    vector_instance->data[vector_instance->length] = *data;
    vector_instance->length++;
}

static void vector_constructor(vector *vector_instance) {

    vector_instance->push_back = &push_back;
    vector_instance->length = 0;
    vector_instance->capacity = 2;
    vector_instance->data = (int*)malloc(sizeof(*vector_instance->data) * vector_instance->capacity);

}

static void vector_destructor(vector *vector_instance) {

    free(vector_instance->data);
    vector_instance->length = 0;
    vector_instance->capacity = 0;
    vector_instance->data = NULL;
}

Main.c

#include <stdio.h>
#include "vector.c"
#include <time.h>

static int isPrime (const int *number) {

    if((*number & 1) == 0) {
        if(*number == 2)
            return 1;
        else
            return 0;
    }

    for(int i = 3; (i * i) <= *number; i += 2) {

        if((*number % i) == 0)
            return 0;
    }

    return *number != 1;
}

int main(int argc, const char * argv[]) {
    vector v;
    vector_constructor(&v);
    clock_t start = clock();
    for(int i = 0; i <= 30000000; i++) {

        if(isPrime(&i))
            v.push_back(&v, &i);
    }
    clock_t end = clock();
    clock_t seconds = (end - start) / CLOCKS_PER_SEC;
    printf("%lu seconds \n", seconds);

    for(int i = 0; i < v.length; i++) {

        //printf("%d \n", v.data[i]);
    }
    vector_destructor(&v);
    return 0;
}

我使用内置的 Clang 编译器在我的 OS X Mavericks 上编译这两个程序。

C++

g++ -O3 -std=c++11 Main.cpp

C

gcc -O3 -std=c99 Main.c

两者都可以毫无问题地编译,并且它们也可以毫无问题地运行。 不过..

我得到不同的时间结果。

C 在 12 秒后完成

C++ 在 26 秒后完成

谁能指出我做错了什么? 谢谢!

【问题讨论】:

  • 您的代码不太一样 - isPrime 中的循环具有不同的增量。不知道这是否会有所作为。
  • 有趣的是,您的 C 代码通过函数指针调用 push_back,它仍然比您的 C++ 快得多。但我认为不同的循环增量是性能差异的主要原因。您的 C++ 版本的模数可能是 C 版本的两倍。
  • 另外,STL vector 可能有不同的扩容规则。如果它使用capacity *= 1.5,它将调用new 更多次。
  • @DrewMcGowen 我认为这会有很大的不同。 C++ 版本检查的分区数量是原来的两倍,运行时间大约是原来的两倍。
  • @Daniel,尝试进行两个不同的测试。首先 - 在 C 和 C++ 中添加向量 N 个数字,其次 - 检查 IsPrime(...) M 次。这将帮助您了解问题出在哪里,在函数中还是在向量中。我猜想在 C 中增加 +2 与在 C++ 中增加 +1 可能会使 C++ 中的操作增加两倍,所以这可能是您的结果的原因。

标签: c++ c performance benchmarking


【解决方案1】:

您的程序在isPrime 中略有不同。在您的 C++ 程序中:

for(int i = 3; (i * i) <= number; i++) {

在你的 C 程序中:

for(int i = 3; (i * i) <= *number; i += 2) {

因此,您的 C++ 程序计算余数的次数大约是 C 程序的两倍,这很可能解释了您的性能差异。

除此之外,我建议您不要通过引用或指针传递int,除非您有充分的理由。希望编译器足够聪明,能够发现您不需要并优化它,但谁知道呢?

此外,您希望尽可能避免通过函数指针调用函数,就像您在 C 程序中所做的那样。它们通常会损害编译器内联优化函数的能力。这里可能是编译器足够聪明,无论如何都可以内联调用,但谁知道呢?

最后,如果计算所有小于 N 的素数确实是您所追求的,而这并不是对 C 与 C++ 进行基准测试的玩具,那么请查看 Sieve of EratosthenesSieve of Sundaram。或者,您可以将已知素数的向量传递给isPrime,并仅检查已知素数而不是所有奇数。

【讨论】:

  • 谢谢,这帮助很大。但是,它仍然慢了 4 秒。我还监督了其他事情吗?
  • 其他人评论说,vector 的常见实现每次将其容量增加 1.5 而不是 2。您可以将您的 C 程序更改为每次增长 1.5 而不是 2,看看这是否完全缩小了差距。
  • 我也改了,越来越近了。 C在11秒后完成。 C++ 在 13 秒后完成。我想这对我来说已经足够了 :)
  • @RobK 希望您的意思是 vector.reserve(5761455); 而不是使用逗号运算符!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-14
  • 1970-01-01
  • 1970-01-01
  • 2023-04-09
  • 2011-01-21
  • 1970-01-01
相关资源
最近更新 更多