一道关于性能方面的难题

PHizingHelen 2016-03-15 04:27:56
加精
直接进入主题:我有一个单例的类,在这个类里面,保存了很多以map或hashmap存放的超重资源。该单例类被其它线程访问,获取数据。目前的做法是这样的:
for (i = 0; i < 20; i++)
{
构造一个超重资源的临时变量;
加读锁
查找单例类,根据key查找value,把value整个拷贝给临时变量;
解读锁;
外面直接使用临时变量做其它操作;
}

上述流程已经实现了大部分的业务,现在从profile工具的结果来看,"把value整个拷贝给临时变量"占了大部分的性能,导致上述流程性能低下。必须找到一个简单而有效的方法,大面积改造这些现有代码。

另外说明的是,之所以用临时变量,并发是第一要素,第二要素是解锁之后的操作也是繁重的,放入锁内得不偿失。如果不复制到临时变量,比如直接从临界区传出指针,则面临着单例类在更新或删除资源时,有可能出现临界区外的指针失效而死机。
...全文
2233 48 打赏 收藏 转发到动态 举报
写回复
用AI写文章
48 条回复
切换为时间正序
请发表友善的回复…
发表回复
zilaishuichina 2016-03-30
  • 打赏
  • 举报
回复
class 超重资源 { // 具体属性 mutex m_ObjLock; // 每份超重资源一个锁,所有对超重资源的多线程访问由超重资源自己负责线程安全 }; for (i = 0; i < 20; i++) { 加读锁 查找单例类,根据key查找value,返回value的指针或引用; 解读锁; 外面直接使用value的指针或引用做其它操作; }
欧阳春晖 2016-03-26
  • 打赏
  • 举报
回复
我们不知道性能分析数据,不能进行判断
chehw_1 2016-03-26
  • 打赏
  • 举报
回复
建两个层级的引用计数,然后每次只传递指针。 先分析出value的结构体中具体是那些部分在复制时消耗资源,把结构体改写如下: struct A { int id; int a; ... int n; // 以上为轻量级资源 struct DATA_TYPE * heavy; // 在A中只保存重量级资源的指针,并对该指针添加引用计数 }; 0. 主线程用一个数组存储所有A结构体的指针,并对每个A的指针添加引用计数。例如: struct A * a[20] = { ... }; 1. 每次传递时,主线程(M)只将对应的A的指针传递给其他线程(T),线程(T)在加锁的情况下,将整个结构体复制到一个临时变量中,并同时将A指针和 a->heavy指针的引用计数分别 + 1,复制操作完成后再解锁; 2. 线程(T)处理完毕后,在加锁的状态下,将A指针和 a->heavy指针的引用计数分别 -1, 当发现某个指针的引入计数为0时,即释放(delete/free)该指针。 3. 当主线程的数据更新时, (a) 如果只涉及到轻量级数据的修改,那么直接操作即可(这些数据已经在同步状态下有了正确的拷贝)。 (b) 如果涉及到重量级资源的修改,那么先分配一份新内存new_pointer,拷贝数据至new_pointer中,然后在加锁的情况下, 另a->heavy = new_pointer, 同时将原heavy指针的引用计数-1。 (c) 如果涉及到数据删除,那么先分配一个新的A结构体,在加锁的情况下,替换原来的A指针,并将A指针的引用计数-1。
scy2510 2016-03-26
  • 打赏
  • 举报
回复
本来都觉得是不是要数据之类的操作的。
scy2510 2016-03-26
  • 打赏
  • 举报
回复
更多仅凭理论设想,请大神看看推理对不对? 本来都觉得是不是要数据之类的操作的。 想了一圈下来觉得最终还是在拷贝和繁重计算上。 超重数据的拷贝和繁重的计算的方式不改变的化,优化都只是假像,只际上是在考验硬件性能(含多核),最终输出结果都要那么久。 就好像反复从硬盘进行程序启动和退出过程,始终要那么久吧。 所以从两个方面来改善 从硬件资源出发 假设是单核的话,就不要拷贝出来了。 低优先级线程用于查找和计算,全过程完了之后,再放开资源(将资源锁成只读)。 高优先级线程用于修改,如果检查资源被锁,那么就将修改按指今(操作和数据)的方式缓存起来(可能会满)。 高优先级线程用于单独读取,先查找原始资源,然后再将缓存中的更新合并过来。 一个单独线程(优先级待定)用于同步缓存到原始资源。 如果上述合理的话,多核应该怎么平衡??以便充分利用硬件资源。 从优化拷贝和繁重计算出发 以单核为例 尽量避免繁重操作,不会完全避免。 还是不要拷贝了,拷贝是硬伤(或者类似OS中页面那样分页拷贝来缓解,也就是将数据存了两份) 让繁重计算化简,在每一份数据中增加额外记录,记录上次计算之后每一“步”的中间结果,每个中间结果对应称一个状态吧(1,,M,N)。下次进入计算前,检查当前数据块所作的修改(在修改时需要标记),分析需要更新那些计算,分析并直接进入到对应状态M开始计算,即每次计算之前,从最需要计算的入口开始计算,去掉不必要的重复的计算来提高平均计算速度。需要对数据的组织比较好。 还可以采用一个低优先级线程,在空闭时,对修改过的数据块进行刷新,使之计算为最新,以便下次需要计算时,直接提取结果即可。 请看看有没有可行性?
hellomworld 2016-03-26
  • 打赏
  • 举报
回复
马克学习一下
PHizingHelen 2016-03-25
  • 打赏
  • 举报
回复
To jiqiang01234:
我以为我实现的引用计数,类似于智能指针。

数据有多重,举个例子:
struct A
{
int id;
string name;
string desc;
vector<int> label;
string chinese_name;
string english_name;
string config;
string authcode;
vector<struct> icon;
map<string, strcut> infos;
...... // 还有很多
}
jiqiang01234 2016-03-25
  • 打赏
  • 举报
回复
引用 42 楼 PHizingHelen 的回复:
To jiqiang01234: 我以为我实现的引用计数,类似于智能指针。 数据有多重,举个例子: struct A { int id; string name; string desc; vector<int> label; string chinese_name; string english_name; string config; string authcode; vector<struct> icon; map<string, strcut> infos; ...... // 还有很多 }
这些数据里,哪些是只读的,哪些在其他线程修改,需要明确。这样可以把只读的分离出来,不用关心同步保护的分问题。只把可能多线程修改的重点处理。
jiqiang01234 2016-03-25
  • 打赏
  • 举报
回复
[quote=引用 41 楼 ole_master 的回复:] 这和智能指针有什么关系,应该是用数据库或者对象池,什么shared_ptr闻所未闻,c++现在都在搞这种了,怪不得没人用[/quote孤陋寡闻还这么理直气壮
zhizhy 2016-03-23
  • 打赏
  • 举报
回复
看漏 了一个能子,我还奇怪呢
Saingel 2016-03-23
  • 打赏
  • 举报
回复
用shared_ptr,更新把修改换成新建对象覆盖原有智能指针,这样更新时不会影响使用
looklzg1108 2016-03-23
  • 打赏
  • 举报
回复
超重临时变量有多重? 建立索引,在查找线程内只进行索引查找; 建立一个拷贝线程,找到索引后,由拷贝线程进行拷贝。 1:查找和拷贝分开; 2:尽量减少需要拷贝的数据。
ole_master 2016-03-23
  • 打赏
  • 举报
回复
这和智能指针有什么关系,应该是用数据库或者对象池,什么shared_ptr闻所未闻,c++现在都在搞这种了,怪不得没人用
jiqiang01234 2016-03-23
  • 打赏
  • 举报
回复
引用 38 楼 PHizingHelen 的回复:
To jiqiang01234: 看起来,shared_ptr是解决此类问题的一个捷径了。 但我不明白m2的做法。 我需要的是A资源的共享访问,用了m2,又变成互斥访问了。
shared_ptr<>只是解决了对象赋值的开销问题,不能解决共享访问的问题。如果map里有很多数据需要多个线程写操作,这种情况就不好优化了。更多的需要从程序设计来修改,把没必要多线程同时读写的去掉。
PHizingHelen 2016-03-23
  • 打赏
  • 举报
回复
To jiqiang01234:
看起来,shared_ptr是解决此类问题的一个捷径了。
但我不明白m2的做法。
我需要的是A资源的共享访问,用了m2,又变成互斥访问了。
赵4老师 2016-03-22
  • 打赏
  • 举报
回复
赞同2楼
this1518 2016-03-22
  • 打赏
  • 举报
回复
我看标题第一印象 邪恶了
爆豆 2016-03-22
  • 打赏
  • 举报
回复
赵老师的意见不错
tcmakebest 2016-03-18
  • 打赏
  • 举报
回复
我想能不能将只读的单例与可写的临时变量结合,读取时优先从临时变量,没有时取只读单例,写入时只写入临时变量.
kuankuan_qiao 2016-03-18
  • 打赏
  • 举报
回复
加载更多回复(28)

64,646

社区成员

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

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