请教:STL比自己写的链表慢这么多?

cyfage 2010-03-28 08:33:09
请教一下各位达人自己遇到的一个问题:

因为工作需要,自己在动手写一个包含了很多增删改查等函数及其扩展的数据结构的封装类库。
本来想着STL是工业级的应用,已被大家使用了这么多年应该很牢靠,无论如何也比自己写的好很多才对,于是采用的是STL的LIST表结构为基础,进行了大量的拓展和封装。

结果想不到的是,写好的库进行调试时慢得不行,一个不过调用数百次稍复杂内容计算的函数在我的双核计算机上居然要2秒多才得出结果,这还了得!
一开始我以为我写得哪不对,结果反复的查来查去,实在检查不出有哪会耽误这么多时间。
最后实在不行了,我把目光转向到STL上,结果发现了两个问题:

1、如果说一个STL的LIST中最简单的push_back方法,直接调用花费的时间为t的话,那么仅仅经过一次函数的封装,所花费的时间就要增加30%左右,这是绝对无法忍受的,可我又看不出问题在哪里。比如像这样:
ITLI DataStruct::PushBack(BOX *Box, const DATA Data)
{
assert(NULL != Box);

Box->push_back(Data);
//Box->end()指向的不是最后一个元素,而是最后个的后面
return -- Box->end();
}

就以上这么简单的函数,居然运行时所花费的时间比直接push_bak多了30%,请问这是为什么?

2、我自己动手写了个链表,和STL比较添加、删除和push数值的速度,结果发现STL远远比不过自己写的,这让我更加不明白了,STL不是工业级的么?这么多人都在用的为什么还这么慢?
以下是STL的对比代码:
#include <iostream>
#include <fstream>
#include <list>
#include <vector>
#include <algorithm>
#include <time.h>
#include <assert.h>
#include <Windows.h>
using namespace std;

typedef unsigned char DATA;
typedef std::list<DATA> BOX; //基础容器类型
typedef BOX::iterator ITLI; //容器指针类型

void Log(char *szBuz)
{
FILE *fp;
SYSTEMTIME tt;
GetLocalTime(&tt);

char sBuz[200] = "";
sprintf(sBuz, "%d-%d-%d %d:%d:%d %s\n",
tt.wMonth,
tt.wDay,
tt.wHour,
tt.wMinute,
tt.wSecond,
tt.wMilliseconds,
szBuz);
OutputDebugStringA(szBuz);
if((fp = fopen("D:\\Test_STL.txt", "a+")) == NULL)
return ;
if (fwrite(sBuz, sizeof(char), strlen(sBuz), fp ) <= 0 )
return ;
fclose(fp);
}

int main()
{
Log("Start STL");
for (int j = 0; j < 10000; ++ j)
{
BOX *aa = new BOX;
for (int i = 0; i < 100; ++ i)
{
aa->push_back(i);
}
delete aa;
}

Log("Finished STL");
return 0;
}


以下是自己写的测试用的链表:
#ifndef DEFINE_2010_03_28_H_
#define DEFINE_2010_03_28_H_

typedef unsigned char VALUE;

struct DATA
{
VALUE Value;
VALUE DyValue;

DATA *Link;
DATA *Inherit;
};
#endif


#ifndef DATASTRUCT_2010_03_28_H_
#define DATASTRUCT_2010_03_28_H_
#pragma once
#include "Define.h"
#include <time.h>
#include <assert.h>
#include <iostream>
#include <fstream>

class DataStruct
{
public:
DataStruct();
virtual ~DataStruct();

virtual DATA* Create();
virtual DATA* Create(const VALUE Count);
virtual bool PushBack(DATA *Head, const VALUE Value);
virtual bool Destory(DATA *Head);
protected:
private:
};
#endif


#pragma once
#include "DataStruct.h"

DataStruct::DataStruct()
{

}

DataStruct::~DataStruct()
{

}

DATA* DataStruct::Create()
{
DATA *Head = (DATA*)malloc(sizeof(DATA));
memset(Head, 0, sizeof(DATA));

return Head;
}

DATA* DataStruct::Create(const VALUE Count)
{
DATA *Head = Create();
DATA *Temp = Head;
while (NULL != Temp->Link)
{
Temp = Temp->Link;
}

for (VALUE i = 0; i < Count; ++ i)
{
DATA *theNew = (DATA*)malloc(sizeof(DATA));
memset(theNew, 0, sizeof(DATA));
Temp->Link = theNew;
//这时Temp指向的是Head的地址,因此Temp->Link = theNew等于将Head->Link赋值,得到了theNew的地址
Temp = theNew;
//这时再将Temp这个“路标”改向为theNew的地址,以后的Temp其实就是现在的theNew了
//Temp和theNew都是一个指针,代表着一个被指向的地址
//Temp = theNew这句并不是将Next里的数值全部赋给Temp,而是将Temp原先指向的地址改为指向theNew,
//并没有动Temp原先指向的地址里(结构)的数据。
}

return Head;
}

bool DataStruct::Destory(DATA *Head)
{
assert(NULL != Head);

DATA *Temp = Head;
while (NULL != Head->Link)
{
Temp = Head;
Head = Head->Link;
free(Temp);
}
free(Head); //这时Head指向的是最后一个单元,并未删除,因此要记得删
return true;
}

bool DataStruct::PushBack(DATA *Head, const VALUE Value)
{
assert(NULL != Head);

DATA *Temp = Head;
while (NULL != Temp->Link)
{
Temp = Temp->Link;
}

DATA *theNew = (DATA*)malloc(sizeof(DATA));
memset(theNew, 0, sizeof(DATA));
Temp->Link = theNew;
theNew->Value = Value;
return true;
}


#pragma once
#include "DataStruct.h"
#include <Windows.h>
using namespace std;

void Log(char *szBuz)
{
FILE *fp;
SYSTEMTIME tt;
GetLocalTime(&tt);

char sBuz[200] = "";
sprintf(sBuz, "%d-%d-%d %d:%d:%d %s\n",
tt.wMonth,
tt.wDay,
tt.wHour,
tt.wMinute,
tt.wSecond,
tt.wMilliseconds,
szBuz);
OutputDebugStringA(szBuz);
if((fp = fopen("D:\\Test_Link.txt", "a+")) == NULL)
return ;
if (fwrite(sBuz, sizeof(char), strlen(sBuz), fp ) <= 0 )
return ;
fclose(fp);
}

int main()
{
DataStruct *theData = new DataStruct;
Log("Start Link");
for (int j = 0; j < 10000; ++ j)
{
DATA *Temp = theData->Create();
for (int i = 0; i < 100; ++ i)
{
theData->PushBack(Temp, i);
}
theData->Destory(Temp);
}
Log("Finished Link");
delete theData;
return 0;
}


这是最后链表的测试结果:
3-28-8 9:40:484 Start Link
3-28-8 9:41:375 Finished Link
3-28-8 9:43:843 Start Link
3-28-8 9:44:718 Finished Link
3-28-8 9:46:875 Start Link
3-28-8 9:47:765 Finished Link
3-28-8 9:49:578 Start Link
3-28-8 9:50:453 Finished Link
3-28-8 9:51:843 Start Link
3-28-8 9:52:734 Finished Link

0.891
0.875
0.890
0.875
0.891
_____

0.884

这是STL的测试结果:
3-28-8 10:2:750 Start STL
3-28-8 10:4:906 Finished STL
3-28-8 10:6:437 Start STL
3-28-8 10:8:609 Finished STL
3-28-8 10:10:828 Start STL
3-28-8 10:13:0 Finished STL
3-28-8 10:14:406 Start STL
3-28-8 10:16:578 Finished STL
3-28-8 10:33:343 Start STL
3-28-8 10:35:515 Finished STL

2.156
2.172
2.172
2.172
2.172
_____

2.169

大家可以看到,足足慢了1.2~1.3秒左右,这实在是无法忍受而又让人奇怪的。
仅仅是一些简单的操作就可以拖开这么大距离,在复杂的库里进行复杂运算的时候还不知道会怎样呢。
我实在是不明白为什么会这样,请各位大家指点下,谢谢了。
...全文
695 14 打赏 收藏 转发到动态 举报
写回复
用AI写文章
14 条回复
切换为时间正序
请发表友善的回复…
发表回复
vicallee 2011-06-06
  • 打赏
  • 举报
回复
呵,我自己用C做了list和map,经测试,千万条记录的插入,遍历,删除,release版本都比stl的快1-3倍,内存占用是stl的%30至%60,用户代码量则比stl的略小,哈
love514425 2010-07-04
  • 打赏
  • 举报
回复
> 2楼说的不错。
机智的呆呆 2010-03-28
  • 打赏
  • 举报
回复
lz是在realse下测试的吗?
我的测试结果 win7+vc2008 realse(/O2)
3-28-12 52:52:416 Start Link
3-28-12 52:56:410 Finished Link

3-28-12 52:48:485 Start STL
3-28-12 52:52:416 Finished STL
stl中list反而比lz写的list快~~~
FingerStyle 2010-03-28
  • 打赏
  • 举报
回复
一个不过调用数百次稍复杂内容计算的函数在我的双核计算机上居然要2秒多才得出结果,这还了得!
======================
2秒? 你自己的代码有问题吧。
cattycat 2010-03-28
  • 打赏
  • 举报
回复
stl是个标准库,他注重设计和提供范式编程,而且对象放到容器的过程大多都是拷贝的,如果对象比较大,而且数量比较多就比较费时间了。
你自己设计的链表只针对你的应用的,当然就能提高速度。
cyfage 2010-03-28
  • 打赏
  • 举报
回复
说起速度,我才想起来,按照我测试的这种方式,由于我写的是单向链表,越插入数据越慢才对,而LIST是双向链表,应该比我快很多。

按照楼上诸位的说法,那么你们需要用到类似功能的时候都是自己写链表?从我目前的需求来说,STL的速度完全不可能实际运用啊。
BT六眼飞鱼 2010-03-28
  • 打赏
  • 举报
回复
关注中。。。
白云飘飘飘 2010-03-28
  • 打赏
  • 举报
回复
如果是发布版本,速度的差距就会小得多了。stl list的接口都是函数,插入一个元素时函数调用本身的开销非常大,发布版本小的函数都inline 了。
ani_di 2010-03-28
  • 打赏
  • 举报
回复
STL比自己写的慢很正常,因为STL考虑了很多安全因素,还有intrator等,不信你看看源码就清楚了。自己写的数据结构简单,当然速度慢了。当然,安全与扩展性方面必然有些牺牲。
cyfage 2010-03-28
  • 打赏
  • 举报
回复
多谢楼上的各位
问题已经找到了,确实是release版本和debug版本的区别。
STL貌似在DEBUG版本下速度很慢,但在release下则几十上百倍的提高了。
ameigame 2010-03-28
  • 打赏
  • 举报
回复
你试过Release版本了没???
Qlaiaqu 2010-03-28
  • 打赏
  • 举报
回复
你写的是dos,而stl是windows xp,根本不是一个量级的东西,比起来有什么意思。多看看stl源码吧,你会知道什么叫做为了效率无所不用其极。
sico_ 2010-03-28
  • 打赏
  • 举报
回复
应该不致于这么慢的吧
jackyjkchen 2010-03-28
  • 打赏
  • 举报
回复
无论结果如何,但我要说的是STL的速度一直都不是长项,STL只能保证同样的实现复杂度(包含各种安全处理和泛型处理),STL能比你自己写的快

65,210

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧