惰性策略的allocator

Vegertar 2011-08-02 02:09:24
又再看Robert Sedgewick的算法了,看到里面一句,
“能够利用与应用相关的特定知识的程序,常常比用于同样任务的通用程序更高效。内存分配也遵从此定律。一个必须处理不同大小的存储请求的算法不可能知道我们将一直请求某种大小的内存块,因此也不能利用这一点。”

以前看的时候居然被略过去了,然后就写了这么一个分配器,估摸着对链表这类增删频繁的数据结构的存储分配的性能有些改善。大家看看,这东西有啥子实用价值没?


template <typename T>
class lazy_alloc : public std::allocator<T>
{
public:
typedef typename std::allocator<T>::pointer pointer;
typedef typename std::allocator<T>::size_type size_type;

~lazy_alloc()
{
typedef
typename std::map<size_type, std::stack<pointer> >::iterator
map_iter;

map_iter beg = pool.begin(), end = pool.end();
while (beg != end) {
std::stack<pointer> &store = beg -> second;
while (!store.empty()) {
std::allocator<T>::deallocate(store.top(), beg -> first);
store.pop();
}

++beg;
}
}

pointer allocate(size_type n, std::allocator<void>::const_pointer hint = 0)
{
std::stack<pointer> &store = pool[n];
if (store.empty())
return std::allocator<T>::allocate(n, hint);

pointer p = store.top();
store.pop();
return p;
}

void deallocate(pointer p, size_type n)
{
pool[n].push(p);
}

private:
std::map<size_type, std::stack<pointer> > pool;
};

...全文
304 19 打赏 收藏 转发到动态 举报
写回复
用AI写文章
19 条回复
切换为时间正序
请发表友善的回复…
发表回复
Vegertar 2011-08-04
  • 打赏
  • 举报
回复
第三天了,该结贴了。
hpsmouse 2011-08-03
  • 打赏
  • 举报
回复
[Quote=引用 17 楼 vegertar 的回复:]
由于长期潜水, 这次冒泡还是要散个分
[/Quote]
唔……打劫,打劫~
Vegertar 2011-08-03
  • 打赏
  • 举报
回复
由于长期潜水, 这次冒泡还是要散个分
Vegertar 2011-08-03
  • 打赏
  • 举报
回复

// main.cpp

#include "lazy_alloc.hpp"
#include <cassert>
#include <algorithm>
#include <iostream>
#include <iterator>
#include <functional>
#include <list>

using namespace std;

int main(int argc, char *argv[])
{
assert(sizeof(int) == sizeof(float));
#ifndef N
int n = 10;
#else
int n = N;
#endif // N

#ifndef STD
list<int, lazy_alloc<int> > l1;
#else
list<int> l1;
#endif // STD
for (int i = 0; i < n; ++i)
l1.push_back(i);
l1.remove_if(bind2nd(modulus<int>(), 2));

#ifndef STD
list<float, lazy_alloc<float> > l2;
#else
list<float> l2;
#endif // STD
for (int i = 0; i < n; ++i )
l2.push_back(i + 0.1F);

#ifdef OUTPUT
copy(l1.begin(), l1.end(), ostream_iterator<int>(cout, " "));
cout << endl;
copy(l2.begin(), l2.end(), ostream_iterator<float>(cout, " "));
#endif // OUTPUT
cout << endl;
}



今天脑子清醒了。
这种搭建在new/delete上的lazy deallocate,其性能,要跟标准分配器比较起来,实在是很纠结啊。
1) g++ -O2 -Wall -DN=10000000 main.cpp -o lazy
2) g++ -O2 -Wall -DN=10000000 -DSTD main.cpp -o std

去除共有的一些开销影响极少的操作,仔细比较一下
1) 1500万次 operator new,1500万次循环{ stack::top , stack::pop , operator delete } , size为1500万的stack生成和销毁

2) 2000万次operator new, 2000万次operator delete

系统层里实在不好说,依赖new/delete
用户层,
1) 就看stack了。虽然top,和pop的开销是常量级的,但是1500万次的循环跳转,精确起来也是很难度量的。而stack本身,它的生成开销应该比较大,默认的deque在push*时没有块间复制,到底产生多少次operator new还是实现相关,但是其维护的块的释放,这个应该也算O(1)吧,也许。。

2) 500万次 operator new,500万次operator delete。这个还是实现相关。

现在看来,1)和2)开销的比较,果然是极为纠结啊!!!
然后我就进行实际测试。虽然局部特征很严重,但是-------------
在我的机器,重启-运行,重启-运行,结果2)要比1)快了0.5秒

P.S.我真傻,真的。我单知道标准库已经是一个轮子,还妄想在轮子上包一层壳让车子跑得更快。
P.P.S.查看了下记录,两年来冒泡不足十次,现在看情形,要继续潜水了。

价值不大,为了帖子的完整性,代码仍然贴上。

// lazy_alloc.hpp

#ifndef LAZH_ALLOC_HPP
#define LAZH_ALLOC_HPP

#include <limits>
#include <map>
#include <stack>

class lazy_alloc_base
{
class pool_t // class for RAII
{
public:
~pool_t()
{
typedef
std::map<size_t, std::stack<void *> >::iterator
map_iter;

map_iter beg = cache.begin(), end = cache.end();
while (beg != end) {
std::stack<void *> &store = beg -> second;
while (! store.empty()) {
operator delete(store.top());
store.pop();
}

++beg;
}
}

std::stack<void *> & operator[](const size_t &n)
{
return cache[n];
}

private:
std::map<size_t, std::stack<void *> > cache;
};

protected:
static pool_t pool;
};

lazy_alloc_base::pool_t lazy_alloc_base::pool;

template <typename T>
class lazy_alloc;

template <>
class lazy_alloc<void>
{
public:
typedef void * pointer;
typedef const void * const_pointer;
typedef void value_type;

template <typename U>
struct rebind { typedef lazy_alloc<U> other; };
};


template <typename T>
class lazy_alloc : public lazy_alloc_base // now any instance of type lazy_alloc will be sharing the same pool
{
public:
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef T * pointer;
typedef const T * const_pointer;
typedef T & reference;
typedef const T & const_reference;
typedef T value_type;

template <typename U>
struct rebind { typedef lazy_alloc<U> other; };

pointer address(reference value) const
{
return &value;
}

const_pointer address(const_reference value) const
{
return &value;
}

lazy_alloc() throw ()
{ }

lazy_alloc(const lazy_alloc &) throw ()
{ }

template <typename U>
lazy_alloc(const lazy_alloc<U> &) throw ()
{ }

~lazy_alloc() throw ()
{ }

size_type max_size() const throw ()
{
return std::numeric_limits<size_type>::max() / sizeof(value_type);
}

void construct(pointer p, const value_type &value)
{
new(p)value_type(value);
}

void destroy(pointer p)
{
p -> ~T();
}

pointer allocate(size_type n, lazy_alloc<void>::const_pointer hint = 0)
{
std::stack<void *> &store = pool[n];
if (store.empty())
return (pointer)operator new(sizeof(n * sizeof(value_type)));

pointer p = (pointer)store.top();
store.pop();
return p;
}

void deallocate(pointer p, size_type n)
{
pool[n].push(p);
}
};

template <typename T, typename U>
bool operator==(const lazy_alloc<T> &, const lazy_alloc<U> &) throw ()
{ return true; }

template <typename T, typename U>
bool operator!=(const lazy_alloc<T> &, const lazy_alloc<U> &) throw ()
{ return false; }

#endif // LAZH_ALLOC_HPP

xiaoyuanyuan2009 2011-08-02
  • 打赏
  • 举报
回复
祝你好运
hpsmouse 2011-08-02
  • 打赏
  • 举报
回复
不知道这个 Allocator 和 free list 实现的内存池比起来怎么样?

我的感觉是 free list 实现的内存池可以很方便地把许多小内存分配合并成一个较大的内存分配请求,调用底层分配函数的次数比较少,也不用缓存每个分配出去的指针。

P.S. 其实 glibc 的 malloc/free 函数在分配小内存的时候就是用的内存池,所以通常情况下我还是比较相信标准库的内存分配效率的~

P.P.S. 楼主貌似有相当长一段时间木有冒泡了啊……
Vegertar 2011-08-02
  • 打赏
  • 举报
回复
用list试了下,发现析构次数过于频繁。

近一年没写C++了,果然是够烂的。

唔,今天programming的时间已经结束,帖子放这,欢迎大家拍砖,明天12点再来。

Vegertar 2011-08-02
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 hpsmouse 的回复:]
Allocator 只要符合 requirements 就行了,不用继承的……

而且那个 std::map 是不是应该 static 一下……
[/Quote]

原本用继承只是想少写一些代码的,写迭代器是写习惯了,一行行的typedef实在是枯燥。

本拟写空的COPY-CTOR的,听你这么一说,static对存储器的利用率更高一些。
healer_kx 2011-08-02
  • 打赏
  • 举报
回复
咕~~(╯﹏╰)b
老朽不行了,都是早年试图学习的粗浅的东西,Lazy这个,不知道有意义没? 个人感觉不搞服务器,浏览器本身这些项目,Allocator的意义都不是很显著。
pengzhixi 2011-08-02
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 healer_kx 的回复:]
引用 4 楼 babilife 的回复:

allocator今天还看了一篇博客,争论激烈,地址忘了,不过我看见甘草了,哈哈

?? ...
[/Quote]
如果我没猜错,是陈硕的一篇关于allocator的博文
healer_kx 2011-08-02
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 babilife 的回复:]

allocator今天还看了一篇博客,争论激烈,地址忘了,不过我看见甘草了,哈哈
[/Quote]
?? ...
hpsmouse 2011-08-02
  • 打赏
  • 举报
回复
Allocator 只要符合 requirements 就行了,不用继承的……

而且那个 std::map 是不是应该 static 一下……
Vegertar 2011-08-02
  • 打赏
  • 举报
回复
使用了成员数据,却没有显式的copy-ctor,果然是乱七八糟啊。
Vegertar 2011-08-02
  • 打赏
  • 举报
回复
据说C++和JAVA都很牛的甘草某某某。。。
Vegertar 2011-08-02
  • 打赏
  • 举报
回复
缺陷比较多,果然还是得按标准规范来写。

哥一直都在自言自语。
babilife 2011-08-02
  • 打赏
  • 举报
回复
allocator今天还看了一篇博客,争论激烈,地址忘了,不过我看见甘草了,哈哈
Vegertar 2011-08-02
  • 打赏
  • 举报
回复
唔,发现一个很严重的bug,rebind 类也被继承了,真实的分配器又重新被定向到了std::allocator了。

方便而又麻烦的继承。
Vegertar 2011-08-02
  • 打赏
  • 举报
回复
呃,是语文经验。
Vegertar 2011-08-02
  • 打赏
  • 举报
回复
第一句话就有语法错误了,多年的语言经验,汗。。。
内容概要:本文围绕不确定环境下的多式联运路径优化问题展开研究,提出并实现了基于AFO算法、遗传算法(GA)和粒子群优化算法(PSO)的三种智能优化方法,并借助Matlab平台完成算法编程与仿真。研究构建了考虑时间、成本、转运风险等多重不确定因素的路径优化模型,系统比较了AFO、GA、PSO三种算法在收敛速度、全局寻优能力和稳定性方面的表现,同时引入Matlab自带的全局优化搜索器作为基准对照,深入分析各算法在复杂物流网络中的适用边界与性能差异。研究表明,AFO算法在解决此类组合优化问题时展现出更快的收敛效率和更强的局部规避能力。; 适合人群:具备一定Matlab编程基础与运筹优化知识,从事物流工程、交通运输规划、智能算法开发等相关领域的研究生、科研人员及工程技术人员。; 使用场景及目标:①应用于多式联运、综合货运网络中的路径决策支持系统构建;②为不确定性条件下复杂路径规划问题提供智能算法选型依据与技术实现方案;③支持科研人员复现主流优化算法并开展横向性能对比实验,推动算法改进与实际落地。; 阅读建议:建议读者结合提供的Matlab代码逐模块分析算法实现流程,重点理解目标函数设计、约束条件处理及参数敏感性分析部分,可通过调整问题规模与算法参数进行对比实验,进一步拓展至动态路径规划或大规模网络优化等延伸场景。
内容概要:本文研究了基于QLearning自适应强化学习的PID控制器在自主水下航行器(AUV)运动控制中的应用,通过Matlab代码实现了控制算法的仿真验证。该方法融合强化学习的在线自适应能力与传统PID控制的稳定性优势,利用QLearning算法动态优化PID控制器的比例、积分、微分参数,以应对水下复杂流体环境、模型不确定性及外部干扰等挑战,从而提升AUV轨迹跟踪的精度、鲁棒性与动态响应性能。文中系统阐述了AUV的六自由度非线性动力学建模过程、QLearning算法的状态空间与动作空间设计、奖励函数构造及训练机制,并详细说明了PID参数自整定的闭环控制架构。仿真结果表明,相较于传统固定参数PID控制器,该智能控制策略在多种工况下均展现出更优的控制效果,有效抑制了超调,加快了响应速度,并增强了抗干扰能力。; 适合人群:具备自动控制理论、强化学习基础及Matlab/Simulink仿真能力,从事水下机器人、智能控制、海洋工程、自动化等领域的研究生、科研人员及工程技术人员。; 使用场景及目标:①应用于AUV、UUV等无人水下平台的高精度自主导航与运动控制;②为解决非线性、强耦合、时变系统的控制器参数自适应整定问题提供智能化解决方案;③作为强化学习与经典控制理论深度融合的技术范例,推动智能控制算法在海洋装备中的工程化应用。; 阅读建议:建议读者结合提供的Matlab代码深入理解算法实现细节,重点剖析QLearning的状态-动作-奖励机制设计、PID参数更新逻辑及仿真对比实验结果,有条件者可在更复杂的动力学模型或实际硬件平台上进一步验证与优化算法性能。

65,211

社区成员

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

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