STD deque на удивление медленный

Я просто выясняю, что стандартная процедура std очень медленная при сравнении с моей «домашней» версией стека, в котором используется предварительно выделенный массив.
Это код моего стека:

template <class T>
class FastStack
{
public:
T* st;
int allocationSize;
int lastIndex;

public:
FastStack(int stackSize);
FastStack();
~FastStack();

inline void resize(int newSize);
inline void push(T x);
inline void pop();
inline T getAndRemove();
inline T getLast();
inline void clear();
};

template <class T>
FastStack<T>::FastStack()
{
lastIndex = -1;
st = NULL;
}

template <class T>
FastStack<T>::FastStack(int stackSize)
{
st = NULL;
this->allocationSize = stackSize;
st = new T[stackSize];
lastIndex = -1;
}

template <class T>
FastStack<T>::~FastStack()
{
delete [] st;
}

template <class T>
void FastStack<T>::clear()
{
lastIndex = -1;
}

template <class T>
T FastStack<T>::getLast()
{
return st[lastIndex];
}

template <class T>
T FastStack<T>::getAndRemove()
{
return st[lastIndex--];
}

template <class T>
void FastStack<T>::pop()
{
--lastIndex;
}

template <class T>
void FastStack<T>::push(T x)
{
st[++lastIndex] = x;
}

template <class T>
void FastStack<T>::resize(int newSize)
{
if (st != NULL)
delete [] st;
st = new T[newSize];
}

.
Я запускаю этот простой тест для deque:

std::deque<int> aStack;
int x;

HRTimer timer;
timer.Start();

for (int i = 0; i < 2000000000; i++)
{
aStack.push_back(i);
x = aStack.back();
if (i % 100 == 0 && i != 0)
for (int j = 0; j < 100; j++)
aStack.pop_back();
}

double totalTime = timer.Stop();
stringstream ss;
ss << "std::deque " << totalTime;
log(ss.str());

.
Использование стека std с вектором в качестве контейнера (как предложено «Michael Kohne»)

std::stack<int, std::vector<int>> bStack;
int x;

HRTimer timer;
timer.Start();

for (int i = 0; i < 2000000000; i++)
{
bStack.push(i);
x = bStack.top();
if (i % 100 == 0 && i != 0)
for (int j = 0; j < 100; j++)
bStack.pop();
}

double totalTime = timer.Stop();
stringstream ss;
ss << "std::stack " << totalTime;
log(ss.str());

.
И тот же самый для моего FastStack:

FastStack<int> fstack(200);
int x;

HRTimer timer;
timer.Start();

for (int i = 0; i < 2000000000; i++)
{
fstack.push(i);
x = fstack.getLast();
if (i % 100 == 0 && i != 0)
for (int j = 0; j < 100; j++)
fstack.pop();
}

double totalTime = timer.Stop();
stringstream ss;
ss << "FastStack " << totalTime;
log(ss.str());

.
Результаты после 4 прогонов следующие:
deque 15.529
deque 15.3756
deque 15.429
deque 15.4778

стек 6.19099
стек 6.1834
стек 6.19315
стек 6.19841

FastStack 3.01085
FastStack 2.9934
FastStack 3.02536
FastStack 3.00937

Результаты в секундах, и я запускал код на Intel i5 3570k (по умолчанию часы). Я использовал компилятор VS2010 со всеми возможными оптимизациями.
Я знаю, что мой FastStack имеет много ограничений, но есть множество ситуаций, где его можно использовать и когда он может дать хороший импульс! (Я использовал его в одном проекте, где я получаю ускорение в 2 раза по сравнению с std :: queue).
Итак, теперь мой вопрос:
Существуют ли какие-либо другие «ингибиторы» в C ++, которые все используют, но никто не знает о них?
РЕДАКТИРОВАТЬ: Я не хочу быть оскорбительным, мне просто любопытно, если вы знаете некоторые неизвестные «ускорения», как это.

7

Решение

Вы сравниваете яблоки и апельсины. У очереди двойное окончание, что требует, чтобы она несколько отличалась внутренне от простого стека, который вы реализовали. Попробуйте запустить свой тест на std::stack<int, std::vector<int> > вместо этого и посмотрите, как вы делаете. std :: stack является контейнерным адаптером, и если вы используете вектор в качестве основного контейнера, он должен быть почти таким же быстрым, как ваша домашняя реализация.

С другой стороны, у реализации std :: stack нет способа предварительно установить размер, поэтому в ситуациях, когда вы ЗНАЕТЕ, какой максимальный размер должен быть, изначально он будет немного медленнее, так как он должен перераспределяться несколько раз. После этого все будет примерно так же.

21

Другие решения

Если вы знаете максимальное количество элементов, которые будут в стеке в любой момент времени, вы должны использовать std::vector на котором вы резервируете емкость заранее. Даже если вы не знаете емкость, для стека вы должны использовать std::vector который будет расти в несколько раз (более высокая стоимость, чем предварительно выделенный вектор при росте), но никогда не будет уменьшаться, поэтому через некоторое время он прекратит выделять память.

Проблема с производительностью заключается в том, что std::deque будет распределять блоки по мере необходимости и освобождать их, когда они больше не нужны (следуя некоторой стратегии), поэтому, если вы заполните и очистите std::deque часто будут постоянно выделяться и освобождаться.

14

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector