免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: kanhfshiys
打印 上一主题 下一主题

[C] 如何写程序就能尽量做到节省内存?或者是提高效率?  关闭 [复制链接]

论坛徽章:
0
31 [报告]
发表于 2009-12-01 01:09 |只看该作者
还是自己去学习吧!

论坛徽章:
0
32 [报告]
发表于 2009-12-01 02:47 |只看该作者
基本同意17楼的. 我说下我的理解吧:
优化分成很多层次, 1)设计层次,2)C代码实现,3)汇编代码实现. 其中的3)基本上由编译器做掉了, 程序员可以控制的不多,最多是选下优化策略,比如GCC的O1,O2,O3. 或者VS的速度优先还是节省空间优先.

在优化之前,首先要明确目标. 节省空间和提高效率并不一定可以同时做到,有时还会互相矛盾. 所以你要明确到底是节省空间重要,还是提高速度更重要.

其次,要明确程序的什么地方是效率最低的,需要优化的. 我觉得大多数情况下, 20/80原理基本适用. 也就是说20%的代码占掉了80%的空间或者时间. 所以重点是优化那20%的代码.其他部分没必要太费心. 类似的,程序员要知道那些操作是浪费时间或者空间的. 费时的操作有:I/O, SYSTEM CALL,没用的PRINTF等. 浪费空间的的例子比如一个很大的数组,实际上用到的很少几个元素. 关于如何找到效率最低的代码部分,可以利用各种PROFILE工具.

最后,举1,2个设计阶段优化的例子.
例子1, 假设你的程序要多次处理一个文件,这时有2种做法. 做法1,每次要处理文件时打开文件,处理完关闭. 做法2,只打开一次文件,然后把内容保存到内存里.后面直接对内存里的数据操作,最后再看情况是否写回文件.
做法1节省空间,但是浪费时间. 做法2浪费一些空间但是节省时间. 最后怎么做就看文件的大小以及打开的次数到底多不多来看了.

例子2, 假设你有一个定时器,每过一段时间就做一些事情.那么这个定时器的间隔时间就是一个重要的参数. 间隔1秒和间隔10的差别不言而喻. 在满足设计要求的情况下,间隔时间越长,占用的CPU时间越少.

总之,设计的时候先明确要实现的目标,然后在满足设计目标的前提下进行优化.

论坛徽章:
0
33 [报告]
发表于 2009-12-01 08:36 |只看该作者
时间和空间是矛盾。

论坛徽章:
0
34 [报告]
发表于 2009-12-01 10:26 |只看该作者
这个问题真要较真,分分钟要说到0和1上去!
经验是在工作中累积的,不断的思考别人写的代码,反思自己写的代码,相信慢慢的会有收获!
没有千篇一律的好代码,更没有绝对的坏代码!特别是现在编译器为我们做了太多事!

论坛徽章:
0
35 [报告]
发表于 2009-12-01 11:16 |只看该作者
原帖由 cugb_cat 于 2009-11-29 14:19 发表

去看APUE的相关章节


APUE关于存储空间的布局讲的不多啊。

论坛徽章:
0
36 [报告]
发表于 2009-12-01 15:27 |只看该作者
说了半天都是废话...

论坛徽章:
0
37 [报告]
发表于 2009-12-01 16:26 |只看该作者

回复 #36 hansion3406 的帖子

那我就也多在线程上废点儿话

其实大家恨线程都是在说线程比进程需要更多的管理。不过大家要注意一点就是,管理是需要成本的。就好比领导赚的多了,成本自然增加了

论坛徽章:
0
38 [报告]
发表于 2009-12-01 17:01 |只看该作者
我真没看懂上面控诉多线程的理由
线程里面lock太多  那也是有并发访问的时候才要lock啊。 你如果多近程并发访问同一个数据,不也要同步么。
如果怕某个线程挂掉影响其他业务而用多进程那我能理解。
而效率上,多进程比多线程怎么会好呢?如果你各个进程可以不用访问临界资源,那我多线程为什么不可以啊。

论坛徽章:
0
39 [报告]
发表于 2009-12-01 18:13 |只看该作者
我也觉得楼上说的有道理,如果线程满篇是lock,那应该也可以说明设计的有问题吧?

论坛徽章:
8
CU大牛徽章
日期:2013-04-17 10:59:39CU大牛徽章
日期:2013-04-17 11:01:45CU大牛徽章
日期:2013-04-17 11:02:15CU大牛徽章
日期:2013-04-17 11:02:36CU大牛徽章
日期:2013-04-17 11:02:58技术图书徽章
日期:2013-12-04 10:48:50酉鸡
日期:2014-01-03 10:32:30辰龙
日期:2014-03-06 15:04:07
40 [报告]
发表于 2009-12-01 18:22 |只看该作者
这是个坚硬的软话题……

说它坚硬,不妨来看看这个聊聊几行、却值得写一篇学术论文论证的简短程序:

http://blog.csdn.net/iamlazybone/archive/2009/07/30/4393973.aspx

原创  神秘的0x5f3759df之卡马克的开平方算法  收藏

通过《DOOM启示录》 了解了卡马克和罗梅洛的传奇故事...

这是卡马克的一个开平方算法...

  1. # float kamake_sqr(float number) {     
  2. #     long i;     
  3. #     float x, y;     
  4. #     const float f = 1.5F;     
  5. #     x = number * 0.5F;     
  6. #     y = number;     
  7. #     i = *(long *) &y;     
  8. #     i = 0x5f3759df - (i >> 1);     
  9. #     y = *(float *) &i;     
  10. #     y = y * (f - (x * y * y));     
  11. #     y = y * (f - (x * y * y));     
  12. #     return number * y;     
  13. # }     
  14. #     
  15. # main() {     
  16. #     printf("sqr(100)=%f", kamake_sqr(100.0));     
  17. #     getch();     
  18. # }  
复制代码

输出:sqr(100)=9.999964

算法里面求平方根一般采用的是无限逼近的方法,比如牛顿迭代法,

比如求5的平方根,选一个猜测值比如2,那么我们可以这么算
5/2 = 2.5; 2.5+2/2 = 2.25; 5/2.25 = xxx; 2.25+xxx/2 = xxxx ...

这样反复迭代下去,结果必定收敛于sqrt(5)

卡马克牛就牛在选择了0x5f3759df 这个开始值,使得迭代的时候收敛速度暴涨,对于Quake III所要求的精度10的负三次方,只需要一次迭代就能够得到结果。

附加一个小故事:

普渡大学的数学家Chris Lomont看了以后觉得有趣,决定要研究一下卡马克弄出来的这个猜测值有什么奥秘。Lomont也是个牛人,在精心研究之后从理论上也推导出一个最佳猜测值,和卡马克的数字非常接近, 0x5f37642f。卡马克真牛,他是外星人吗?

传奇并没有在这里结束。Lomont计算出结果以后非常满意,于是拿自己计算出的起始值和卡马克的神秘数字做比赛,看看谁的数字能够更快更精确的求得平方根。结果是卡马克赢了... 谁也不知道卡马克是怎么找到这个数字的。

最后Lomont怒了,采用暴力方法一个数字一个数字试过来,终于找到一个比卡马克数字要好上那么一丁点的数字,虽然实际上这两个数字所产生的结果非常近似,这个暴力得出的数字是0x5f375a86。

Lomont为此写下一篇论文,"Fast Inverse Square Root"。


还有这里: http://tbl.javaeye.com/blog/231425

有兴趣的可以搜下看看相关的论文,看看伟大的卡马克究竟是怎样从这样一些细节开始,把传统的3D算法优化提速10倍之多,以至于我们在486上即可提前享受到3D游戏。

PS:我记得这个游戏最小系统需求好像是486 DX66。
  换句话说,如果没有卡马克,PC上第一款320*240像素的3D游戏需要推迟接近5~8年才能出现——也就是说,到了2000年,你就可以在一台650M以上CPU的电脑上玩320*240像素的全屏3D游戏了。


而这个开平方取倒数算法,不过“仅仅”是把标准库里的 float (1.0/sqrt(x)) 加速了2~4倍而已。

可是,里面用到的那个magic number的选取原理,即便有了专门的论文,我敢说也没几个人能看懂。


那么,这么艰深的话题,有几个人有那么好的牙口,可以啃得动?




可是,另一方面,看看java库当年那个著名的“字符串副本”问题——那么简单,那么低级的小问题,造成了多大的困扰。

这时候,性能/效率问题,又似乎不过是一点点常识而已——是个每个人都可以参与、都可以去捏的软柿子。





于是,不可避免的,又有很多人开始纷纷扰扰: ++i还是i++,究竟怎么写性能才高?一个复杂公式,写成一个表达式快,还是分成几行清晰的写出来快?嵌套if快,还是switch快?for快,还是while快,抑或是do while快?……

一时间,各种各样的“高速”写法闹得一片乌烟瘴气,以至于不得不有人出来高呼: 千万别过早优化,20%的代码占用了80%的处理时间,先写程序,找出那20%代码就好了!



可是,反过来说难道不对吗?一个你意想不到的、极其细微的设计缺陷,就可能导致机器把80%的性能浪费于其上——就如同java那个字符串多次复制bug一样——你怎么敢不在每一个细节上都精打细算?

考虑到越在后面阶段发现的bug将越难修改;那么一个架构设计导致的性能问题,究竟会扯动多么大的一片代码?
(我的亲身经历: 一个已经投入了5000万、开发了的项目,因为数据库设计太差必须返工;而这个数据库设计要返工,那么整个系统就必须从头写,因为所有的模块都和数据库相关!)

甚至于,如果每一万行中,有2000行的的代码可能拖慢2%的性能,而整个软件有100万行代码——这个系统你又该如何优化?
干脆要用户拿3倍的硬件投资来获得和竞争对手一样的性能?
还是回头去优化2000*100=20万行代码?——当然,你还得先在100万行代码中找到这20万行瓶颈代码。

——很多时候,性能问题不是因为一个问题引入的,而是被很多很多罗罗嗦嗦的东西一步步拖累死的。

那么,你为什么不早点做优化?为什么非要拖到性能问题已不可收拾之时?



说白了,性能问题,就是一个人的知识水平问题。

对卡马克等大牛来说,他的代码就是要字斟句酌,就是要在每个细节上都把性能压榨干净——但,看他的代码,有模糊、臃肿、怪异之感吗?
清澈如水。你什么都看的清清楚楚,但,却有很多地方,别人就是给你解释,你都不一定能懂。

相反,对刚刚入门的普通程序员来说,首先把代码写干净、写规范,这个任务就已经很不容易了。
至于性能,将来找热点再优化吧。

至于中高级程序员呢,把代码写干净、写规范已经是很容易的事情了;那么下一步,就是敲入每行代码前都要想一想,看看究竟怎么才会快——但同时又绝对不能影响可读性。


换句话说: 把代码写的干净、整齐、易懂,是一件不需努力就可以做到的事;而把机器的性能充分压榨出来,则需要更多更深刻的知识打底。

你的知识积累越多,做蠢事的机会就越少,敲进去的代码执行速度就越快——没有什么小经验小技巧可以让你一步登天。

而在此之前,必须知道,编码规范不会影响任何人——包括卡马克。
沉迷于炫耀那些立竿见影的、表驱动的switch快于逐次跳转的if之类的“小技巧”“小聪明”,却忽略了包括编码规范在内的基本功,只会让你永远都理解不了卡马克那大白话一般的代码——甚至是断送作为程序员的职业前景。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP