到目前为止,我用C编写了我的代码(性能至关重要)。但是,我想开始以通用的方式编写算法。所以,我决定试用C ++。我在C中使用了一个简单的代码,并将其转换为带有模板的C ++。令我失望的是,C ++代码的运行速度慢了2.5倍。 (C代码用gcc -O3编译; C ++代码用g ++ -O3编译)
我在C ++中做错了什么?为什么会出现这样的性能影响?
这是C代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
static int df_output = 0;
int nCalls = 0;
typedef struct {
int *pancakes;
int n;
} STATE;
STATE **solution;
void shuffle(STATE *s) {
int i;
for (i = 0; i < s->n; i++) {
int i1 = rand() % s->n;
int i2 = rand() % s->n;
int temp = s->pancakes[i1];
s->pancakes[i1] = s->pancakes[i2];
s->pancakes[i2] = temp;
}
}
STATE *copyState(STATE *s) {
STATE *res = malloc(sizeof(STATE));
res->n = s->n;
res->pancakes = (int *)malloc(res->n * sizeof(int));
memcpy(res->pancakes, s->pancakes, res->n * sizeof(int));
return res;
}
// reverse n pancakes
void makeMove(STATE *s, int n) {
int i;
for (i = 0; i < n/2; i++) {
int temp = s->pancakes[i];
s->pancakes[i] = s->pancakes[n - 1 - i];
s->pancakes[n - 1 - i]=temp;
}
}
void printState(STATE *s) {
int i;
printf("[");
for (i = 0; i < s->n; i++) {
printf("%d", s->pancakes[i]);
if (i < s->n - 1)
printf(", ");
}
printf("]");
}
int heuristic(STATE *s) {
int i, res = 0;
nCalls++;
for (i = 1; i < s->n; i++)
if (abs(s->pancakes[i]-s->pancakes[i-1])>1)
res++;
if (s->pancakes[0] != 0) res++;
return res;
}
void tabs(int g) {
int i;
for (i = 0; i < g; i++) printf("\t");
}
int df(STATE *s, int g, int left) {
int h = heuristic(s), i;
if (g == 0) printf("Thereshold: %d\n", left);
if (df_output) {
tabs(g);
printf("g=%d,left=%d ", g, left); printState(s); printf("\n");}
if (h == 0) {
assert(left == 0);
solution = (STATE **)malloc((g+1) * sizeof(STATE *));
solution[g] = copyState(s);
return 1;
}
if (left == 0)
return 0;
for (i = 2; i <= s->n; i++) {
makeMove(s, i);
if (df(s, g+1, left-1)) {
makeMove(s, i);
solution[g] = copyState(s);
return 1;
}
makeMove(s, i);
}
return 0;
}
void ida(STATE *s) {
int threshold = 0, i;
while (!df(s, 0, threshold)) threshold++;
for (i = 0; i <= threshold; i++) {
printf("%d. ", i);
printState(solution[i]);
printf("\n");
//if (i < threshold - 1) printf("->");
}
}
int main(int argc, char **argv) {
STATE *s = (STATE *)malloc(sizeof(STATE));
int i, n;
int myInstance[] = {0,5,4,7,2,6,1,3};
s->n = 8;
s->pancakes = myInstance;
printState(s); printf("\n");
ida(s);
printf("%d calls to heuristic()", nCalls);
return 0;
}
这是C ++代码:
#include <iostream>
#include "stdlib.h"
#include "string.h"
#include "assert.h"
using namespace std;
static int df_output = 0;
int nCalls = 0;
class PancakeState {
public:
int *pancakes;
int n;
PancakeState *copyState();
void printState();
};
PancakeState *PancakeState::copyState() {
PancakeState *res = new PancakeState();
res->n = this->n;
res->pancakes = (int *)malloc(this->n * sizeof(int));
memcpy(res->pancakes, this->pancakes,
this->n * sizeof(int));
return res;
}
void PancakeState::printState() {
int i;
cout << "[";
for (i = 0; i < this->n; i++) {
cout << this->pancakes[i];
if (i < this->n - 1)
cout << ", ";
}
cout << "]";
}
class PancakeMove {
public:
PancakeMove(int n) {this->n = n;}
int n;
};
class Pancake {
public:
int heuristic (PancakeState &);
int bf(PancakeState &);
PancakeMove *getMove(int);
void makeMove(PancakeState &, PancakeMove &);
void unmakeMove(PancakeState &, PancakeMove &);
};
int Pancake::bf(PancakeState &s) {
return s.n - 1;
}
PancakeMove *Pancake::getMove(int i) {
return new PancakeMove(i + 2);
}
// reverse n pancakes
void Pancake::makeMove(PancakeState &s, PancakeMove &m) {
int i;
int n = m.n;
for (i = 0; i < n/2; i++) {
int temp = s.pancakes[i];
s.pancakes[i] = s.pancakes[n - 1 - i];
s.pancakes[n - 1 - i]=temp;
}
}
void Pancake::unmakeMove(PancakeState &state, PancakeMove &move) {
makeMove(state, move);
}
int Pancake::heuristic(PancakeState &s) {
int i, res = 0;
nCalls++;
for (i = 1; i < s.n; i++)
if (abs(s.pancakes[i]-s.pancakes[i-1])>1)
res++;
if (s.pancakes[0] != 0) res++;
return res;
}
void tabs(int g) {
int i;
for (i = 0; i < g; i++) cout << "\t";
}
template <class Domain, class State, class Move>
class Alg {
public:
State **solution;
int threshold;
bool verbose;
int df(Domain &d, State &s, int g);
void ida(Domain &d, State &s);
};
template <class Domain, class State, class Move>
int Alg<Domain, State, Move>::df(Domain &d, State &s, int g) {
int h = d.heuristic(s), i;
if (g == 0)
cout << "Thereshold:" << this->threshold << "\n";
if (this->verbose) {
tabs(g);
cout << "g=" << g;
s.printState(); cout << "\n";
}
if (h == 0) {
solution = (State **)malloc((g+1) * sizeof(State *));
solution[g] = s.copyState();
return 1;
}
if (g == this->threshold)
return 0;
for (i = 0; i < d.bf(s); i++) {
Move *move = d.getMove(i);
d.makeMove(s, *move);
if (this->df(d, s, g+1)) {
d.unmakeMove(s, *move);
solution[g] = s.copyState();
delete move;
return 1;
}
d.unmakeMove(s, *move);
delete move;
}
return 0;
}
template <class Domain, class State, class Move>
void Alg<Domain, State, Move>::ida(Domain &d, State &s) {
int i;
this->threshold = 0;
while (!this->df(d, s, 0)) threshold++;
for (i = 0; i <= threshold; i++) {
cout << i << ".";
this->solution[i]->printState();
cout << "\n";
//if (i < threshold - 1) printf("->");
}
}
int main(int argc, char **argv) {
Pancake *d = new Pancake();
PancakeState *s = new PancakeState();
int myInstance[] = {0,5,4,7,2,6,1,3};
s->pancakes = myInstance;
s->n = 8;
s->printState(); cout << "\n";
Alg<Pancake, PancakeState, PancakeMove> *alg = new Alg<Pancake, PancakeState, PancakeMove>();
//alg->verbose = true;
alg->ida(*d, *s);
cout << nCalls < "calls to heuristic()";
delete alg;
return 0;
}
答案 0 :(得分:2)
你有很多malloc()和operator new调用。停止这样做,性能将提高。并且不要在C ++中使用malloc(),总是使用operator new。
例如,PancakeMove是一个小而简单的结构。但是你动态分配它的实例,这很慢。只需按价值传递它。
答案 1 :(得分:2)
基本上,你在堆上而不是堆栈上分配了很多小东西。这非常“昂贵”,所以需要额外的时间。
此代码(从原始代码修改)在C代码的1ms内运行:
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <vector>
using namespace std;
static int df_output = 0;
int nCalls = 0;
class PancakeState {
public:
PancakeState(int n) : n(n), pancakes(n)
{
}
PancakeState(int n, int *v) : n(n), pancakes(n)
{
for(int i = 0; i < n; i++)
pancakes[i] = v[i];
}
PancakeState(): n(0) {}
public:
vector<int> pancakes;
int n;
PancakeState *copyState();
void printState();
};
void PancakeState::printState() {
int i;
cout << "[";
for (i = 0; i < this->n; i++) {
cout << this->pancakes[i];
if (i < this->n - 1)
cout << ", ";
}
cout << "]";
}
class PancakeMove {
public:
PancakeMove(int n) : n(n) {}
int n;
};
class Pancake {
public:
int heuristic (PancakeState &);
int bf(PancakeState&);
PancakeMove getMove(int);
void makeMove(PancakeState &, PancakeMove &);
void unmakeMove(PancakeState &, PancakeMove &);
};
int Pancake::bf(PancakeState& s) {
return s.n - 1;
}
PancakeMove Pancake::getMove(int i) {
return PancakeMove(i + 2);
}
// reverse n pancakes
void Pancake::makeMove(PancakeState &s, PancakeMove &m) {
int i;
int n = m.n;
for (i = 0; i < n/2; i++) {
int temp = s.pancakes[i];
s.pancakes[i] = s.pancakes[n - 1 - i];
s.pancakes[n - 1 - i]=temp;
}
}
void Pancake::unmakeMove(PancakeState &state, PancakeMove &move) {
makeMove(state, move);
}
int Pancake::heuristic(PancakeState &s) {
int i, res = 0;
nCalls++;
for (i = 1; i < s.n; i++)
if (abs(s.pancakes[i]-s.pancakes[i-1])>1)
res++;
if (s.pancakes[0] != 0) res++;
return res;
}
void tabs(int g) {
int i;
for (i = 0; i < g; i++) cout << "\t";
}
template <class Domain, class State, class Move>
class Alg {
public:
vector<State> solution;
int threshold;
bool verbose;
int df(Domain &d, State &s, int g);
void ida(Domain &d, State &s);
};
template <class Domain, class State, class Move>
int Alg<Domain, State, Move>::df(Domain &d, State &s, int g) {
int h = d.heuristic(s), i;
if (g == 0)
cout << "Thereshold:" << threshold << "\n";
if (this->verbose) {
tabs(g);
cout << "g=" << g;
s.printState(); cout << "\n";
}
if (h == 0) {
solution.resize(g+1);
solution[g] = s;
return 1;
}
if (g == this->threshold)
return 0;
for (i = 0; i < d.bf(s); i++) {
Move move = d.getMove(i);
d.makeMove(s, move);
if (this->df(d, s, g+1)) {
d.unmakeMove(s, move);
solution[g] = s;
return 1;
}
d.unmakeMove(s, move);
}
return 0;
}
template <class Domain, class State, class Move>
void Alg<Domain, State, Move>::ida(Domain &d, State &s) {
int i;
this->threshold = 0;
while (!this->df(d, s, 0)) threshold++;
for (i = 0; i <= threshold; i++) {
cout << i << ".";
solution[i].printState();
cout << "\n";
//if (i < threshold - 1) printf("->");
}
}
int main(int argc, char **argv) {
Pancake d = Pancake();
int myInstance[] = {0,5,4,7,2,6,1,3};
PancakeState s(8, myInstance);
s.printState(); cout << "\n";
Alg<Pancake, PancakeState, PancakeMove> *alg = new Alg<Pancake, PancakeState, PancakeMove>();
//alg->verbose = true;
alg->ida(d, s);
cout << nCalls < "calls to heuristic()";
delete alg;
return 0;
}
作为不进行如此多直接分配的额外好处,它在整个执行过程中也不会泄漏22个内存块,这是非常有用的功能。
(如果你想看看改变了什么,这里有一个差异 - 忽略空白只会改变):
--- pcake.orig.cpp 2014-04-13 15:43:24.861417827 +0100
+++ pcake.cpp 2014-04-13 15:42:25.145165372 +0100
@@ -1,7 +1,9 @@
#include <iostream>
-#include "stdlib.h"
-#include "string.h"
-#include "assert.h"
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <vector>
+
using namespace std;
static int df_output = 0;
@@ -9,21 +11,22 @@
class PancakeState {
public:
- int *pancakes;
+ PancakeState(int n) : n(n), pancakes(n)
+ {
+ }
+ PancakeState(int n, int *v) : n(n), pancakes(n)
+ {
+ for(int i = 0; i < n; i++)
+ pancakes[i] = v[i];
+ }
+ PancakeState(): n(0) {}
+public:
+ vector<int> pancakes;
int n;
PancakeState *copyState();
void printState();
};
-PancakeState *PancakeState::copyState() {
- PancakeState *res = new PancakeState();
- res->n = this->n;
- res->pancakes = (int *)malloc(this->n * sizeof(int));
- memcpy(res->pancakes, this->pancakes,
- this->n * sizeof(int));
- return res;
-}
-
void PancakeState::printState() {
int i;
cout << "[";
@@ -37,25 +40,25 @@
class PancakeMove {
public:
- PancakeMove(int n) {this->n = n;}
+ PancakeMove(int n) : n(n) {}
int n;
};
class Pancake {
public:
int heuristic (PancakeState &);
- int bf(PancakeState &);
- PancakeMove *getMove(int);
+ int bf(PancakeState&);
+ PancakeMove getMove(int);
void makeMove(PancakeState &, PancakeMove &);
void unmakeMove(PancakeState &, PancakeMove &);
};
-int Pancake::bf(PancakeState &s) {
+int Pancake::bf(PancakeState& s) {
return s.n - 1;
}
-PancakeMove *Pancake::getMove(int i) {
- return new PancakeMove(i + 2);
+PancakeMove Pancake::getMove(int i) {
+ return PancakeMove(i + 2);
}
// reverse n pancakes
@@ -91,7 +94,7 @@
template <class Domain, class State, class Move>
class Alg {
public:
- State **solution;
+ vector<State> solution;
int threshold;
bool verbose;
int df(Domain &d, State &s, int g);
@@ -102,30 +105,28 @@
int Alg<Domain, State, Move>::df(Domain &d, State &s, int g) {
int h = d.heuristic(s), i;
if (g == 0)
- cout << "Thereshold:" << this->threshold << "\n";
+ cout << "Thereshold:" << threshold << "\n";
if (this->verbose) {
tabs(g);
cout << "g=" << g;
s.printState(); cout << "\n";
}
if (h == 0) {
- solution = (State **)malloc((g+1) * sizeof(State *));
- solution[g] = s.copyState();
+ solution.resize(g+1);
+ solution[g] = s;
return 1;
}
if (g == this->threshold)
return 0;
for (i = 0; i < d.bf(s); i++) {
- Move *move = d.getMove(i);
- d.makeMove(s, *move);
+ Move move = d.getMove(i);
+ d.makeMove(s, move);
if (this->df(d, s, g+1)) {
- d.unmakeMove(s, *move);
- solution[g] = s.copyState();
- delete move;
+ d.unmakeMove(s, move);
+ solution[g] = s;
return 1;
}
- d.unmakeMove(s, *move);
- delete move;
+ d.unmakeMove(s, move);
}
return 0;
}
@@ -138,23 +139,22 @@
for (i = 0; i <= threshold; i++) {
cout << i << ".";
- this->solution[i]->printState();
+ solution[i].printState();
cout << "\n";
//if (i < threshold - 1) printf("->");
}
}
int main(int argc, char **argv) {
- Pancake *d = new Pancake();
- PancakeState *s = new PancakeState();
+ Pancake d = Pancake();
int myInstance[] = {0,5,4,7,2,6,1,3};
- s->pancakes = myInstance;
- s->n = 8;
- s->printState(); cout << "\n";
+ PancakeState s(8, myInstance);
+ s.printState(); cout << "\n";
Alg<Pancake, PancakeState, PancakeMove> *alg = new Alg<Pancake, PancakeState, PancakeMove>();
//alg->verbose = true;
- alg->ida(*d, *s);
+ alg->ida(d, s);
cout << nCalls < "calls to heuristic()";
delete alg;
return 0;
}
+