快乐的天空

时间来得快,去得也快

 

程序员的七个建议

如果你喜欢编程,那么你真是受到了上天的眷顾。你是非常幸运的少数人之一,能够以自己喜欢的事谋生。大多数人没有这么幸运。你认为理所当然的观念 “热爱你的工作”,其实是一个很现代的概念。通常的看法是,工作是一种让人很不开心的事,你为了拿工资才不得不去上班。你工作的目的是为了攒下钱去干那些 自己真正喜欢干的事,但是前提是你得等到65岁退休之后才行,而且还有不少条件。条件一,你的积蓄必须足够多;条件二,你没有老到走不动,你还有体力去干 那些事情;条件三,你喜欢的事情不需要用到脆弱的膝盖、昏花的视力,也不要求你走上一里地不喘气,等等。

  我刚才说到哪里了?对了,我要提建议。

  毕业前练好写作

   如果不是Linus Torvalds不断地散布福音,请问Linux操作系统会成功吗?虽然他是一个非常聪明的计算机天才,但是Linux吸引来全世界一大批志愿者的真正原 因却是Linus Torvalds的表达能力。他通过电子邮件和邮件列表用书面形式传播自己的想法,最终引起了所有人的注意。

  你听说过现在风靡一时的“极限编程[ ] ”(Extreme Programming)吗?我在这个地方不谈我对极限编程的看法,我只说如果你听过这个词,那么原因就是它的倡导者都是一些非常有才华的作家和演说家。

  即使我们缩小范围,将目光局限在任何一个软件开发团体中,你也会发现该团体中最有权势和影响力的程序员正是那些表达能力强的程序员,他们无论是做书面表达还是做口头表达,都能够清晰、自如、具有说服力地传达观点。此外,长得高也有助于提升影响力,不过这个不取决于你。

   一个普通程序员与一个优秀程序员的区别,不在于他们懂得的编程语言谁多谁少,也不在于他们喜欢用Python语言还是喜欢用Java语言,而在于他们能 否与他人交流思想。如果你能说服其他人,你的力量就可以得到放大。如果你能写出清晰的注释和技术规格说明书,其他程序员就能够理解你的代码,因此他们就能 在自己的代码中使用,而不必重写。如果你做不到这一点,你的代码对其他人就没有价值。如果你能为最终用户写出清晰的使用手册,其他人就能明白你的代码是用 来干什么的,这是唯一让别人明白你的代码有何价值的方法。SourceForge[ ]上有许多优美的、有用的代码,但是它们都像被埋葬了一样,根本没人来用,原因就是它们的作者没有写好使用说明(或者压根就没写)。这样一来就没有人知道 他们的成果,他们杰出的代码就衰亡了。

  如果一个程序员不会用英语写作、没有良好的写作能力,我就不会雇他。如果你能写,不管你去哪家公司工作,你很快就会发现写作技术文档的任务会落到你头上,这意味着你已经开始在放大自己的影响力了,管理层正在注意到你。

  大学里有些课程被公认为“写作密集型”(writing intensive)课程,这就是说为了拿到学分,你必须写作多得可怕的文字。一定要去上这样的课程!不要管学科,只要这门课每周甚至每天都要你写东西,你就去上。

  你还可以动手写日记或者网志。你写得越多,写作就会变得越容易。写起来越容易,你就会写得越多。这是一个良性循环。

  毕业前学好C语言

   第二点我要讲的是C语言。请注意,我说的是C语言,而不是C++。虽然在实际使用中C语言已经越来越罕见,但是它仍然是当前程序员的共同语言。C语言让 程序员互相沟通,更重要的是,它比你在大学中学到的“现代语言”(比如ML语言、Java语言、Python语言或者其它正在教授的流行垃圾语言)都更接 近机器。你至少需要花一个学期来了解机器原理,否则你永远不可能在高级语言的层次写出高效的代码。你也永远无法开发编译器和操作系统,而它们恰恰属于目前 程序员能够得到的最佳工作之列。别人也永远不会放心将大型项目的架构设计交给你。我不管你懂多少延续(continuation)、闭包 (closure)、异常处理(exception handling),只要你不能解释为什么while (*s++ = *t++);这句代码的作用是复制字符串,或者不觉得这是世界上对你来说再自然不过的事情,那么你就是在盲目无知的情况下编程。在我看来,这就好像一个医 生不懂得最基本的解剖学就在开处方,他看病的根据完全是因为那些娃娃脸的医药厂商销售代表说这种药有用。

  毕业前学好微观经济学

   如果你没有上过任何经济学课程,那么我首先来做一个超短的评论:经济学是这样的学科之一,刚开始学的时候轰轰烈烈,有许多有用的、言之有理的理论和可以 在真实世界中得到证明的事实,等等;但是,再学下去就每况愈下,有用的东西就不多了。经济学一开始那个有用的部分正是微观经济学,它是商业领域所有重要理 论的基础。跟在微观经济学后面的东西就不行了。你接下来学的是宏观经济学,如果你愿意,尽管跳过去,也不会有什么损失。宏观经济学开头的部分是利息理论, 内容比方说是利率与失业之间的关系,但是怎么说呢,看上去这部分里面还没有被证实的东西多于已经被证实的东西。学完这部分,后面的内容越来越糟糕,许多经 济学专业的学生实际上都变成在搞物理学,因为这样才能在华尔街上找到更好的工作。但是不管怎样,你一定要去学微观经济学,因为你必须搞懂供给和需求,你必 须明白竞争优势,你必须理解什么是净现值(NPV),什么是贴现,什么是边际效用。只有这样,你才会懂得为什么生意是现在这种做法。

  为 什么计算机系的学生也应该学经济学?因为,从经营一家公司的角度来看,比起那些不懂的程序员,一个理解基本商业规则的程序员将会更有价值。就是这么简单。 我无法告诉你有多少次我是那样地充满挫折感,因为我看到了太多的提出一些疯狂的想法的程序员,这些想法在代码上也许可行,但在资本主义世界中毫无意义。如 果你懂得商业规则,你就是一个更有价值的程序员,你会因此得到回报的,但是前提是你要去学习微观经济学。

  不要因为枯燥就不选修非计算机专业的课程。

   想提高GPA绩点的一个好方法就是多选修非计算机系的课程。请千万不要低估你的GPA的重大意义。千千万万的人事经理和招聘人员在拿到一份简历的时候, 第一眼就会去看GPA,包括我也是这样。我们不会为这种做法道歉。为什么?因为GPA不反映单个的成绩,而是代表了许多个教授在一段很长的时间中,在不同 的情况下,对你的表现的一个总的评估。SAT成绩难道不够吗?哈,那只不过是一场几个小时的测试罢了。GPA中包括了四年大学期间你的小论文、期中考试和 课堂表现,总数有几百次之多。当然,GPA也有自己的问题,不是百分之百准确。比如,这些年来,老师对学生的打分越来越宽松,学习成绩有通货膨胀的趋势。 再比如,GPA无法反映课程的难度,没人能够看出你的GPA是来自无名社区大学家政系的轻松课程还是来自加州理工学院针对研究生的量子力学课程。渐渐地, 我形成了一套自己的做法,首先我会过滤掉所有来自社区大学、GPA低于2.5的简历,然后我会要求剩下的人给我寄成绩单和推荐信。我再从中发现那些成绩一 贯优秀的人,而不是那些仅仅在计算机系课程中得到高分的人。

  为什么我要关心某人的“欧洲历史”课程成绩呢,毕竟作为雇主我要找的应该是 程序员啊?何况,历史是那么枯燥,不得高分很正常。哦,这么说来,你的意思是我应该雇用你,而不用考虑一旦工作变得枯燥你会不会努力工作?别忘了,在编程 工作中也有很枯燥的东西。每一项工作都有枯燥难耐的时刻。我不想雇用那些只想干有趣事情的人。

  选修有大量编程实践的课程

  我依然清楚记得我发誓绝不读研究生的那一刻。那是在一门叫做“动态逻辑”的课程上,教师是活力十足的耶鲁大学教授Lenore Zuck,她是计算机系那些聪明的老师中最聪明的人之一。

   如今, 由于记忆力糟糕, 我已经差不多把这门课的内容忘光了,但是不管怎么说,在这里我还是想要对付着说一下。大致上,形式逻辑的意思是说,如果条件成立,你就能证明结论也成立。 比如,根据形式逻辑,已知“只要成绩好,就能被雇用”,然后假定“Johnny的成绩好”,你就可以得到一个崭新的结论“Johnny会被雇用”。这完全 是经典方法。但是,一个解构主义者(deconstructionist)只需要10秒钟就能破坏形式逻辑中所有有用的东西。这样一来,留给你的只是一些 趣味性,而不是实用性。

  现在再来说动态逻辑。它与形式逻辑其实是一回事,但是必须再多考虑时间因素。比如,“你打开灯之后,就能看见自己的鞋子”,已知“灯以前是亮的”,那么这就意味着“你看见了自己的鞋子”。

   对于像Zuck教授那样聪明的理论家,动态逻辑充满了吸引力,因为它看上去很有希望让你在形式上证明一些计算机程序的相关理论问题。这样做说不定很有 用。比如,你可以用它在形式上证明,火星漫游车的闪存卡不会发生溢出(overflow)问题,不会因而整天一遍又一遍地重启,耽误了它在那颗赤红色的星 球上漫游寻找火星人马文(Marvin the Martian)。

  在第一堂课上,Zuck博士写满了整整两面黑板,甚至黑板旁边的墙上都写上了很多证明步骤。需要证明的问题是,有一个控制灯泡的开关,现在灯泡没有亮,这时你打开了开关,请证明灯泡将会点亮。

   整个证明过程复杂得不可思议,处处都是陷阱,必须十分小心。保证这个证明不出错太困难了,还不如直接相信打开开关灯就会亮。真的,虽然证明过程写满了许 多块黑板,但是还是有许多中间步骤被省略了,因为如果要从形式逻辑上完整证明所有步骤,那就琐碎得无法形容了。许多步骤是用各种经典的逻辑证明方法推导得 到的,包括归纳法、反证法等,甚至有些部分还是由旁听的研究生证明的。

  留给我们的课后作业是证明逆命题:如果灯原来是关着的,现在却亮了,那么请证明开关的状态一定同原来相反。

  我动手开始证明,我真的去证明了。

  我在图书馆里待了很长时间。

   我对照着Zuck博士的原始证明想依样画葫芦。研究了几个小时之后,我在其中发现了一个错误。可能我抄写的时候抄错了,但是这使得我想通了一件事。如果 花费3个小时,写满了一块又一块的黑板,每一秒钟都可能出错,最后能够证明的却只是一个很琐碎的结论,那么这种方式有多大的实用性呢?在活生生、充满趣味 的现实世界中,你永远都不会有机会使用它。

  但是,动态逻辑的理论家们对这一点不感兴趣。他们看上它不是因为它有用,而是因为它可以为他们带来终身教职。

  我放弃了这门课,并且发誓绝不会去读计算机科学的研究生。

   这个故事告诉我们,计算机科学与软件开发不是一回事。如果你真的非常幸运,你的学校可能会开设很像样的软件开发课程。但是另一种可能是,你的学校根本不 教你在现实中如何编程,因为精英学校都觉得,教授工作技能最好留给职业技术学校、犯人重返社会的培训项目去做。你到处都能学怎么写代码。别忘了,我们是耶 鲁大学,我们的使命是培养未来的世界领袖。你交了16万美元的学费,却在学循环语句的写法,这怎么可以?你以为这是什么地方,难道是机场沿途的酒店里临时 拼凑起来不靠谱的Java语言培训班?哼哼。

  麻烦在于我们没有一种真正教授软件开发的专门学校。你如果想成为一个程序员,你可能只能选 择计算机科学专业。这是一个不错的专业,但是它同软件开发不是一回事。在那些400等级的课程代号中,去寻找名称中带有“Practicum”这个词的课 程吧(编者注:指供人实习的课程)。不要被这个拉丁语单词吓倒,这些都是有用的课程,之所以起这种名字,只是为了让那些文绉绉、装腔作势、满嘴胡说八道的 公司经理们觉得高深莫测。

  别担心所有工作都被印度人抢走

  我首先要说的是,如果你本身就已经在印度了,或者你就是印度人,那么你真的毫无必要去想这件事,根本不用琢磨所有的工作机会是不是都跑到了印度。那些都是非常好的工作,好好地享受吧,祝你身体健康。

   但是,我不断听说计算机系的入学人数下降得很厉害,已经到了危险的程度。根据我听到的说法,其中的一个原因是“学生们不愿去学一个工作机会都流向印度的 专业”。这种担心大错特错,有很多理由可以反驳。首先,根据一时性的商业潮流决定个人的职业选择,这是愚蠢的。其次,即使编程工作无一幸存

posted @ 2014-07-08 21:38 探路者 阅读(280) | 评论 (0)编辑 收藏

lua的require机制

 为了方便代码管理,通常会把lua代码分成不同的模块,然后在通过require函数把它们加载进来。
现在看看lua的require的处理流程。

1、require机制相关的数据和函数
    package.path:保存加载外部模块(lua中"模块"和"文件"这两个概念的分界比较含糊,因为这个值在不同的时刻会扮演不同的角色)的搜索 路径,这种路径是"模板式的路径",它里面会包含可替代符号"?",这个符号会被替换,然后lua查找这个文件是否存在,如果存在就会调用其中特定的接 口。典型的值为:
    "./?.lua;./?.lc;/usr/local/?/init.lua"
    如果lua代码中调用:require("hello.world")
    那么lua会依次查找:
    ./hello/world.lua ==>这里"hello.world"变成了"hello/world",并替换了模型"./?.lua"
    ./hello/world.lc
    .....
    (这种处理方式和python类似,只不过不需要__init__.py,也有调用python中的__init__.py)
    package.path在虚拟机启动的时候设置,如果存在环境变量LUA_PATH,那么就用该环境变量作为
    它的值,并把这个环境变量中的";;"替换为luaconf.h中定义的默认值,如果不存在该变量就直接使用
    luaconf.h定义的默认值
    
    package.cpath:作用和packag.path一样,但它是用于加载第三方c库的。它的初始值可以通过环境变量
    LUA_CPATH来设置
    
    package.loadlib(libname, func):相当与手工打开c库libname, 并导出函数func返回,loadlib其实是ll_loadlib
    

2.require的处理流程:
   require(modelname)
   require(在lua中它是ll_require函数)的查找顺序如下:
       a.首先在package.loaded查找modelname,如果该模块已经存在,就直接返回它的值
       b.在package.preload查找modelname, 如果preload存在,那么就把它作为loader,调用loader(L)
       c.根据package.path的模式查找lua库modelname,这个库是通过module函数定义的,对于顶层的lua库,文件名和库名是一 样的而且不需要调用显式地在lua文件中调用module函数(在ll_require函数中可以看到处理方式),也就是说lua会根据lua文件直接完 成一个loader的初始化过程。
       d.根据package.cpath查找c库,这个库是符合lua的一些规范的(export具有一定特征的函数接口),lua先已动态的方式加载该c库,然后在库中查找并调用相应名字的接口,例如:luaopen_hello_world
       e.已第一个"."为分割,将模块名划分为:(main, sub)的形式,根据package.cpath查找main,如果存在,就加载该库并查询相应的接口:luaopen_main_sub,例如:先查找 hello库,并查询luaopen_hello_world接口
       f.得到loder后,用modname作为唯一的参数调用该loader函数。当然参数是通过lua的栈传递的,所以loader的原型必须符合lua的规范:int LUA_FUNC(lua_State *L)
         
       ll_require会将这个loader的返回值符给package.loaded[modelname],如果loader不返回值同时 package.loaded[modelname]不存在时, ll_require就会把package.loaded[modelname]设为true。最后ll_reuqire把package.loaded [modelname]返回给调用者。
    

3.module的处理流程
    module(name, cb1, cb2, ...)
    
    a.如果package.loaded[name]是一个table,那么就把这个table作为一个mod
    b.如果全局变量name是一个table,就把这个全局变量作为一个mod
    c.创建table:t = {[name]=package.loaded[name], ["_NAME"]=name, ["_M"]=t, ["_PACKAGE"]=*name*(删除了最后的".XXXX"部分)}. 如果name是一个以点分割的串,那么得到的mod类似这个样子:
      hello.world==> {["hello"]={["world"]={XXXXXXX}}}
    d.依次调用cbs:
      cb1(mod), cb2(mod),...
      
    e.将当前模块的环境设置为mod,同时把package.loaded[name] = mod 

posted @ 2014-07-01 08:49 探路者 阅读(378) | 评论 (0)编辑 收藏

redis 参数配置

1. Redis默认不是以守护进程的方式运行,可以通过该配置项修改,使用yes启用守护进程

    daemonize no

2. 当Redis以守护进程方式运行时,Redis默认会把pid写入/var/run/redis.pid文件,可以通过pidfile指定

    pidfile /var/run/redis.pid

3. 指定Redis监听端口,默认端口为6379,作者在自己的一篇博文中解释了为什么选用6379作为默认端口,因为6379在手机按键上MERZ对应的号码,而MERZ取自意大利歌女Alessia Merz的名字

    port 6379

4. 绑定的主机地址

    bind 127.0.0.1

5.当 客户端闲置多长时间后关闭连接,如果指定为0,表示关闭该功能

    timeout 300

6. 指定日志记录级别,Redis总共支持四个级别:debug、verbose、notice、warning,默认为verbose

    loglevel verbose

7. 日志记录方式,默认为标准输出,如果配置Redis为守护进程方式运行,而这里又配置为日志记录方式为标准输出,则日志将会发送给/dev/null

    logfile stdout

8. 设置数据库的数量,默认数据库为0,可以使用SELECT <dbid>命令在连接上指定数据库id

    databases 16

9. 指定在多长时间内,有多少次更新操作,就将数据同步到数据文件,可以多个条件配合

    save <seconds> <changes>

    Redis默认配置文件中提供了三个条件:

    save 900 1

    save 300 10

    save 60 10000

    分别表示900秒(15分钟)内有1个更改,300秒(5分钟)内有10个更改以及60秒内有10000个更改。

 

10. 指定存储至本地数据库时是否压缩数据,默认为yes,Redis采用LZF压缩,如果为了节省CPU时间,可以关闭该选项,但会导致数据库文件变的巨大

    rdbcompression yes

11. 指定本地数据库文件名,默认值为dump.rdb

    dbfilename dump.rdb

12. 指定本地数据库存放目录

    dir ./

13. 设置当本机为slav服务时,设置master服务的IP地址及端口,在Redis启动时,它会自动从master进行数据同步

    slaveof <masterip> <masterport>

14. 当master服务设置了密码保护时,slav服务连接master的密码

    masterauth <master-password>

15. 设置Redis连接密码,如果配置了连接密码,客户端在连接Redis时需要通过AUTH <password>命令提供密码,默认关闭

    requirepass foobared

16. 设置同一时间最大客户端连接数,默认无限制,Redis可以同时打开的客户端连接数为Redis进程可以打开的最大文件描述符数,如果设置 maxclients 0,表示不作限制。当客户端连接数到达限制时,Redis会关闭新的连接并向客户端返回max number of clients reached错误信息

    maxclients 128

17. 指定Redis最大内存限制,Redis在启动时会把数据加载到内存中,达到最大内存后,Redis会先尝试清除已到期或即将到期的Key,当此方法处理 后,仍然到达最大内存设置,将无法再进行写入操作,但仍然可以进行读取操作。Redis新的vm机制,会把Key存放内存,Value会存放在swap区

    maxmemory <bytes>

18. 指定是否在每次更新操作后进行日志记录,Redis在默认情况下是异步的把数据写入磁盘,如果不开启,可能会在断电时导致一段时间内的数据丢失。因为 redis本身同步数据文件是按上面save条件来同步的,所以有的数据会在一段时间内只存在于内存中。默认为no

    appendonly no

19. 指定更新日志文件名,默认为appendonly.aof

     appendfilename appendonly.aof

20. 指定更新日志条件,共有3个可选值:
    no:表示等操作系统进行数据缓存同步到磁盘(快)
    always:表示每次更新操作后手动调用fsync()将数据写到磁盘(慢,安全)
    everysec:表示每秒同步一次(折衷,默认值)

    appendfsync everysec

 

21. 指定是否启用虚拟内存机制,默认值为no,简单的介绍一下,VM机制将数据分页存放,由Redis将访问量较少的页即冷数据swap到磁盘上,访问多的页面由磁盘自动换出到内存中(在后面的文章我会仔细分析Redis的VM机制)

     vm-enabled no

22. 虚拟内存文件路径,默认值为/tmp/redis.swap,不可多个Redis实例共享

     vm-swap-file /tmp/redis.swap

23. 将所有大于vm-max-memory的数据存入虚拟内存,无论vm-max-memory设置多小,所有索引数据都是内存存储的(Redis的索引数据 就是keys),也就是说,当vm-max-memory设置为0的时候,其实是所有value都存在于磁盘。默认值为0

     vm-max-memory 0

24. Redis swap文件分成了很多的page,一个对象可以保存在多个page上面,但一个page上不能被多个对象共享,vm-page-size是要根据存储的 数据大小来设定的,作者建议如果存储很多小对象,page大小最好设置为32或者64bytes;如果存储很大大对象,则可以使用更大的page,如果不 确定,就使用默认值

     vm-page-size 32

25. 设置swap文件中的page数量,由于页表(一种表示页面空闲或使用的bitmap)是在放在内存中的,,在磁盘上每8个pages将消耗1byte的内存。

     vm-pages 134217728

26. 设置访问swap文件的线程数,最好不要超过机器的核数,如果设置为0,那么所有对swap文件的操作都是串行的,可能会造成比较长时间的延迟。默认值为4

     vm-max-threads 4

27. 设置在向客户端应答时,是否把较小的包合并为一个包发送,默认为开启

    glueoutputbuf yes

28. 指定在超过一定的数量或者最大的元素超过某一临界值时,采用一种特殊的哈希算法

    hash-max-zipmap-entries 64

    hash-max-zipmap-value 512

29. 指定是否激活重置哈希,默认为开启(后面在介绍Redis的哈希算法时具体介绍)

    activerehashing yes

30. 指定包含其它的配置文件,可以在同一主机上多个Redis实例之间使用同一份配置文件,而同时各个实例又拥有自己的特定配置文件

    include /path/to/local.conf



# By default Redis does not run as a daemon. Use 'yes' if you need it.
# Note that Redis will write a pid file in /var/run/redis.pid when daemonized.
#Redis默认不是以守护进程的方式运行,可以通过该配置项修改,使用yes启用守护进程
daemonize no
# When running daemonized, Redis writes a pid file in /var/run/redis.pid by
# default. You can specify a custom pid file location here.
#当 Redis 以守护进程的方式运行的时候,Redis 默认会把 pid 文件放在/var/run/redis.pid
#可配置到其他地址,当运行多个 redis 服务时,需要指定不同的 pid 文件和端口
pidfile /var/run/redis.pid
# Accept connections on the specified port, default is 6379.
# If port 0 is specified Redis will not listen on a TCP socket.
#端口
port 6379
# If you want you can bind a single interface, if the bind option is not
# specified all the interfaces will listen for incoming connections.
#指定Redis可接收请求的IP地址,不设置将处理所有请求,建议生产环境中设置
# bind 127.0.0.1
# Close the connection after a client is idle for N seconds (0 to disable)
#客户端连接的超时时间,单位为秒,超时后会关闭连接
timeout 0
# Set server verbosity to 'debug'
# it can be one of:
# debug (a lot of information, useful for development/testing)
# verbose (many rarely useful info, but not a mess like the debug level)
# notice (moderately verbose, what you want in production probably)
# warning (only very important / critical messages are logged)
#日志记录等级,4个可选值
loglevel notice
# Specify the log file name. Also 'stdout' can be used to force
# Redis to log on the standard output. Note that if you use standard
# output for logging but daemonize, logs will be sent to /dev/null
#配置 log 文件地址,默认打印在命令行终端的窗口上,也可设为/dev/null屏蔽日志、
logfile stdout
# Set the number of databases. The default database is DB 0, you can select
# a different one on a per-connection basis using SELECT where
# dbid is a number between 0 and 'databases'-1
#设置数据库的个数,可以使用 SELECT 命令来切换数据库。
databases 16
#
# Save the DB on disk:
#
#   save
#
#   Will save the DB if both the given number of seconds and the given
#   number of write operations against the DB occurred.
#
#   In the example below the behaviour will be to save:
#   after 900 sec (15 min) if at least 1 key changed
#   after 300 sec (5 min) if at least 10 keys changed
#   after 60 sec if at least 10000 keys changed
#
#   Note: you can disable saving at all commenting all the "save" lines.
#设置 Redis 进行数据库镜像的频率。保存数据到disk的策略
#900秒之内有1个keys发生变化时
#30秒之内有10个keys发生变化时
#60秒之内有10000个keys发生变化时
save 900 1
save 300 10
save 60 10000
# Compress string objects using LZF when dump .rdb databases?
# For default that's set to 'yes' as it's almost always a win.
# If you want to save some CPU in the saving child set it to 'no' but
# the dataset will likely be bigger if you have compressible values or keys.
#在进行镜像备份时,是否进行压缩
rdbcompression yes
# The filename where to dump the DB
#镜像备份文件的文件名
dbfilename dump.rdb
# The working directory.
#
# The DB will be written inside this directory, with the filename specified
# above using the 'dbfilename' configuration directive.
# Also the Append Only File will be created inside this directory.
# Note that you must specify a directory here, not a file name.
#数据库镜像备份的文件放置的路径
#路径跟文件名分开配置是因为 Redis 备份时,先会将当前数据库的状态写入到一个临时文件
#等备份完成时,再把该临时文件替换为上面所指定的文件
#而临时文件和上面所配置的备份文件都会放在这个指定的路径当中
#默认值为 ./
dir /var/lib/redis/
# Master-Slave replication. Use slaveof to make a Redis instance a copy of
# another Redis server. Note that the configuration is local to the slave
# so for example it is possible to configure the slave to save the DB with a
# different interval, or to listen to another port, and so on.
#设置该数据库为其他数据库的从数据库
#slaveof <masterip> <masterport> 当本机为从服务时,设置主服务的IP及端口
# slaveof
# If the master is password protected (using the "requirepass" configuration
# directive below) it is possible to tell the slave to authenticate before
# starting the replication synchronization process, otherwise the master will
# refuse the slave request.
#指定与主数据库连接时需要的密码验证
#masterauth <master-password> 当本机为从服务时,设置主服务的连接密码
# masterauth
# When a slave lost the connection with the master, or when the replication
# is still in progress, the slave can act in two different ways:
#
# 1) if slave-serve-stale-data is set to 'yes' (the default) the slave will
#    still reply to client requests, possibly with out of data data, or the
#    data set may just be empty if this is the first synchronization.
#
# 2) if slave-serve-stale data is set to 'no' the slave will reply with
#    an error "SYNC with master in progress" to all the kind of commands
#    but to INFO and SLAVEOF.
#当slave丢失与master的连接时,或slave仍然在于master进行数据同步时(未与master保持一致)
#slave可有两种方式来响应客户端请求:
#1)如果 slave-serve-stale-data 设置成 'yes'(默认),slave仍响应客户端请求,此时可能会有问题
#2)如果 slave-serve-stale-data 设置成 'no',slave会返回"SYNC with master in progress"错误信息,但 INFO 和SLAVEOF命令除外。
slave-serve-stale-data yes
# Require clients to issue AUTH before processing any other
# commands.  This might be useful in environments in which you do not trust
# others with access to the host running redis-server.
#
# This should stay commented out for backward compatibility and because most
# people do not need auth (e.g. they run their own servers).
# Warning: since Redis is pretty fast an outside user can try up to
# 150k passwords per second against a good box. This means that you should
# use a very strong password otherwise it will be very easy to break.
#设置客户端连接后进行任何其他指定前需要使用的密码
#redis速度相当快,一个外部用户在一秒钟进行150K次密码尝试,需指定强大的密码来防止暴力破解
# requirepass foobared
# Set the max number of connected clients at the same time. By default there
# is no limit, and it's up to the number of file descriptors the Redis process
# is able to open. The special value '0' means no limits.
# Once the limit is reached Redis will close all the new connections sending
# an error 'max number of clients reached'.
#限制同时连接的客户数量。
#当连接数超过这个值时,redis 将不再接收其他连接请求,客户端尝试连接时将收到 error 信息
# maxclients 128
# Don't use more memory than the specified amount of bytes.
# When the memory limit is reached Redis will try to remove keys
# accordingly to the eviction policy selected (see maxmemmory-policy).
#
# If Redis can't remove keys according to the policy, or if the policy is
# set to 'noeviction', Redis will start to reply with errors to commands
# that would use more memory, like SET, LPUSH, and so on, and will continue
# to reply to read-only commands like GET.
#
# This option is usually useful when using Redis as an LRU cache, or to set
# an hard memory limit for an instance (using the 'noeviction' policy).
#
# WARNING: If you have slaves attached to an instance with maxmemory on,
# the size of the output buffers needed to feed the slaves are subtracted
# from the used memory count, so that network problems / resyncs will
# not trigger a loop where keys are evicted, and in turn the output
# buffer of slaves is full with DELs of keys evicted triggering the deletion
# of more keys, and so forth until the database is completely emptied.
#
# In short... if you have slaves attached it is suggested that you set a lower
# limit for maxmemory so that there is some free RAM on the system for slave
# output buffers (but this is not needed if the policy is 'noeviction').
#设置redis能够使用的最大内存。
#达到最大内存设置后,Redis会先尝试清除已到期或即将到期的Key(设置过expire信息的key
#在删除时,按照过期时间进行删除,最早将要被过期的key将最先被删除
#如果已到期或即将到期的key删光,仍进行set操作,那么将返回错误
#此时redis将不再接收写请求,只接收get请求。
#maxmemory的设置比较适合于把redis当作于类似memcached 的缓存来使用
# maxmemory <bytes>
# By default Redis asynchronously dumps the dataset on disk. If you can live
# with the idea that the latest records will be lost if something like a crash
# happens this is the preferred way to run Redis. If instead you care a lot
# about your data and don't want to that a single record can get lost you should
# enable the append only mode: when this mode is enabled Redis will append
# every write operation received in the file appendonly.aof. This file will
# be read on startup in order to rebuild the full dataset in memory.
#
# Note that you can have both the async dumps and the append only file if you
# like (you have to comment the "save" statements above to disable the dumps).
# Still if append only mode is enabled Redis will load the data from the
# log file at startup ignoring the dump.rdb file.
#
# IMPORTANT: Check the BGREWRITEAOF to check how to rewrite the append
# log file in background when it gets too big.
#redis 默认每次更新操作后会在后台异步的把数据库镜像备份到磁盘,但该备份非常耗时,且备份不宜太频繁
#redis 同步数据文件是按上面save条件来同步的
#如果发生诸如拉闸限电、拔插头等状况,那么将造成比较大范围的数据丢失
#所以redis提供了另外一种更加高效的数据库备份及灾难恢复方式
#开启append only 模式后,redis 将每一次写操作请求都追加到appendonly.aof 文件中
#redis重新启动时,会从该文件恢复出之前的状态。
#但可能会造成 appendonly.aof 文件过大,所以redis支持BGREWRITEAOF 指令,对appendonly.aof重新整理
appendonly no
# The name of the append only file (default: "appendonly.aof")
##更新日志文件名,默认值为appendonly.aof
# appendfilename appendonly.aof
# The fsync() call tells the Operating System to actually write data on disk
# instead to wait for more data in the output buffer. Some OS will really flush 
# data on disk, some other OS will just try to do it ASAP.
#
# Redis supports three different modes:
#
# no: don't fsync, just let the OS flush the data when it wants. Faster.
# always: fsync after every write to the append only log . Slow, Safest.
# everysec: fsync only if one second passed since the last fsync. Compromise.
#
# The default is "everysec" that's usually the right compromise between
# speed and data safety. It's up to you to understand if you can relax this to
# "no" that will will let the operating system flush the output buffer when
# it wants, for better performances (but if you can live with the idea of
# some data loss consider the default persistence mode that's snapshotting),
# or on the contrary, use "always" that's very slow but a bit safer than
# everysec.
#
# If unsure, use "everysec".
#设置对 appendonly.aof 文件进行同步的频率
#always 表示每次有写操作都进行同步,everysec 表示对写操作进行累积,每秒同步一次。
#no表示等操作系统进行数据缓存同步到磁盘,都进行同步,everysec 表示对写操作进行累积,每秒同步一次
# appendfsync always
appendfsync everysec
# appendfsync no
# Virtual Memory allows Redis to work with datasets bigger than the actual
# amount of RAM needed to hold the whole dataset in memory.
# In order to do so very used keys are taken in memory while the other keys
# are swapped into a swap file, similarly to what operating systems do
# with memory pages.
#
# To enable VM just set 'vm-enabled' to yes, and set the following three
# VM parameters accordingly to your needs.
#是否开启虚拟内存支持。
#redis 是一个内存数据库,当内存满时,无法接收新的写请求,所以在redis2.0后,提供了虚拟内存的支持
#但需要注意的,redis 所有的key都会放在内存中,在内存不够时,只把value 值放入交换区
#虽使用虚拟内存,但性能基本不受影响,需要注意的是要把vm-max-memory设置到足够来放下所有的key
vm-enabled no
# vm-enabled yes
# This is the path of the Redis swap file. As you can guess, swap files
# can't be shared by different Redis instances, so make sure to use a swap
# file for every redis process you are running. Redis will complain if the
# swap file is already in use.
#
# The best kind of storage for the Redis swap file (that's accessed at random) 
# is a Solid State Disk (SSD).
#
# *** WARNING *** if you are using a shared hosting the default of putting
# the swap file under /tmp is not secure. Create a dir with access granted
# only to Redis user and configure Redis to create the swap file there.
#设置虚拟内存的交换文件路径,不可多个Redis实例共享
vm-swap-file /tmp/redis.swap
# vm-max-memory configures the VM to use at max the specified amount of
# RAM. Everything that deos not fit will be swapped on disk *if* possible, that
# is, if there is still enough contiguous space in the swap file.
#
# With vm-max-memory 0 the system will swap everything it can. Not a good
# default, just specify the max amount of RAM you can in bytes, but it's
# better to leave some margin. For instance specify an amount of RAM
# that's more or less between 60 and 80% of your free RAM.
#设置开启虚拟内存后,redis将使用的最大物理内存大小。
#默认为0,redis将把他所有能放到交换文件的都放到交换文件中,以尽量少的使用物理内存
#即当vm-max-memory设置为0的时候,其实是所有value都存在于磁盘
#在生产环境下,需要根据实际情况设置该值,最好不要使用默认的 0
vm-max-memory 0
# Redis swap files is split into pages. An object can be saved using multiple
# contiguous pages, but pages can't be shared between different objects.
# So if your page is too big, small objects swapped out on disk will waste
# a lot of space. If you page is too small, there is less space in the swap
# file (assuming you configured the same number of total swap file pages).
#
# If you use a lot of small objects, use a page size of 64 or 32 bytes.
# If you use a lot of big objects, use a bigger page size.
# If unsure, use the default :)
#设置虚拟内存的页大小
如果 value 值比较大,如要在 value 中放置博客、新闻之类的所有文章内容,就设大一点
vm-page-size 32
# Number of total memory pages in the swap file.
# Given that the page table (a bitmap of free/used pages) is taken in memory,
# every 8 pages on disk will consume 1 byte of RAM.
#
# The total swap size is vm-page-size * vm-pages
#
# With the default of 32-bytes memory pages and 134217728 pages Redis will
# use a 4 GB swap file, that will use 16 MB of RAM for the page table.
#
# It's better to use the smallest acceptable value for your application,
# but the default is large in order to work in most conditions.
#设置交换文件的总的 page 数量
#注意page table信息是放在物理内存中,每8个page 就会占据RAM中的 1 个 byte
#总的虚拟内存大小 = vm-page-size * vm-pages
vm-pages 134217728
# Max number of VM I/O threads running at the same time.
# This threads are used to read/write data from/to swap file, since they
# also encode and decode objects from disk to memory or the reverse, a bigger
# number of threads can help with big objects even if they can't help with
# I/O itself as the physical device may not be able to couple with many
# reads/writes operations at the same time.
#
# The special value of 0 turn off threaded I/O and enables the blocking
# Virtual Memory implementation.
#设置 VM IO 同时使用的线程数量。
vm-max-threads 4
# Hashes are encoded in a special way (much more memory efficient) when they
# have at max a given numer of elements, and the biggest element does not
# exceed a given threshold. You can configure this limits with the following
# configuration directives.
#redis 2.0后引入了 hash 数据结构。 
#hash 中包含超过指定元素个数并且最大的元素当没有超过临界时,hash 将以zipmap来存储
#zipmap又称为 small hash,可大大减少内存的使用
hash-max-zipmap-entries 512
hash-max-zipmap-value 64
# Active rehashing uses 1 millisecond every 100 milliseconds of CPU time in
# order to help rehashing the main Redis hash table (the one mapping top-level
# keys to values). The hash table implementation redis uses (see dict.c)
# performs a lazy rehashing: the more operation you run into an hash table
# that is rhashing, the more rehashing "steps" are performed, so if the
# server is idle the rehashing is never complete and some more memory is used
# by the hash table.
# The default is to use this millisecond 10 times every second in order to
# active rehashing the main dictionaries, freeing memory when possible.
#
# If unsure:
# use "activerehashing no" if you have hard latency requirements and it is
# not a good thing in your environment that Redis can reply form time to time
# to queries with 2 milliseconds delay.
#
# use "activerehashing yes" if you don't have such hard requirements but
# want to free memory asap when possible.
#是否重置Hash表
#设置成yes后redis将每100毫秒使用1毫秒CPU时间来对redis的hash表重新hash,可降低内存的使用
#当使用场景有较为严格的实时性需求,不能接受Redis时不时的对请求有2毫秒的延迟的话,把这项配置为no。
#如果没有这么严格的实时性要求,可以设置为 yes,以便能够尽可能快的释放内存
activerehashing yes

Redis官方文档对VM的使用提出了一些建议:
  • 当key很小而value很大时,使用VM的效果会比较好.因为这样节约的内存比较大
  • 当key不小时,可以考虑使用一些非常方法将很大的key变成很大的value,如可将key,value组合成一个新的value
  • 最好使用linux ext3 等对稀疏文件支持比较好的文件系统保存你的swap文件
  • vm-max-threads参数可设置访问swap文件的线程数,最好不要超过机器的核数;设置为0则所有对swap文件的操作都是串行的,可能会造成比较长时间的延迟,但是对数据完整性有很好的保证
redis数据存储
redis的存储分为内存存储、磁盘存储和log文件三部分,配置文件中有三个参数对其进行配置。
  • save seconds updates,save配置,指出在多长时间内,有多少次更新操作,就将数据同步到数据文件。可多个条件配合,默认配置了三个条件。
  • appendonly yes/no ,appendonly配置,指出是否在每次更新操作后进行日志记录,如果不开启,可能会在断电时导致一段时间内的数据丢失。因为redis本身同步数据文件是按上面的save条件来同步的,所以有的数据会在一段时间内只存在于内存中。
  • appendfsync no/always/everysec ,appendfsync配置,no表示等操作系统进行数据缓存同步到磁盘,always表示每次更新操作后手动调用fsync()将数据写到磁盘,everysec表示每秒同步一次。

 

posted @ 2014-06-18 12:57 探路者 阅读(4834) | 评论 (0)编辑 收藏

怎样把梳子卖给和尚

导读:今天跟大家分享一则小故事《怎样把梳子卖给和尚》。想必很多人都已经在别的地方看过这则小故事了。今天小编想带你从另一个角度去解读。

有一个营销经理想考考他的手下,就给他们出了一道题——把梳子卖给和尚。

第一个人:出了门就骂,什么狗经理,和尚都没有头发,还卖什么梳子!找个酒馆喝起了闷酒,睡了一觉,回去告诉经理,和尚没有头发,梳子无法卖!经理微微一笑,和尚没有头发还需要你告诉我?

第二个人:来到了一个寺庙,找到了和尚,对和尚说,我想卖给你一把梳子,和尚说,我没用。那人就把经理的作业说了一遍,说如果卖不出去,就会失业,你要发发慈悲啊!和尚就买了一把。

第三个人:也来到一个寺庙卖梳子,和尚说,真的不需要的。那人在庙里转了转,对和尚说,拜佛是不是要心诚,和尚说,是 的。 心诚是不是需要心存敬意,和尚说,要敬。那人说,你看,很多香客很远来到这里,他们十分虔诚,但是却风尘仆仆,蓬头垢面,如何对佛敬?如果庙里买些梳子, 给这些香客把头发梳整齐了,把脸洗干净了,不是对佛的尊敬?和尚话说有理,就买了十把。

第四个人:也来到一个寺庙卖梳子,和尚说,真的不需要的。那人对和尚说,如果庙里备些梳子作为礼物送给香客,又实惠、又有意义,香火会更旺的。和尚想了想,有道理,就买了100把。

第五个人:也来到一个寺庙卖梳子,和尚说,真的不需要的。那人对和尚说,你是德道高僧,书法甚是有造诣,如果把您的字刻在梳子上,刻些“平安梳”、“积善梳”送给香客,是不是既弘扬了佛法,又弘扬了书法。老和尚微微一笑,善哉!就买了1000把梳子。

第六个人:也来到一个寺庙卖梳子,和尚说,真的不需要的。那个人和和尚说了一番话,却卖出了一万把梳子。那人说了些什么呢?他告诉和尚,梳子是善男信女的必备之物,经常被女香客带是在身上,

如果大师能为梳子开光,成为她们的护身符,既能积善行善、又能保佑平安,很多香客还能为自己的亲朋好友请上一把,保佑平安,弘扬佛法,扬我寺院之名,

岂不是天大善事?大师岂有不做之理?阿弥陀佛,善哉!善哉!大师双手合十,施主有这番美意,老衲岂能不从就这样。寺院买了一万把,取名“积善梳”、“平安梳”,由大师亲自为香客开光,竟十分兴隆。当然,开光所捐的善款也不菲啊!

各位看看

第一个人受传统观念的束缚太厉害,用常理去考虑销售,是不适合做销售的。

第二个人是在卖同情心,这是最低级的销售方法,叫“叩头营销”,是不能长久的。

第三、四人为客户着想,可以说是“顾客满意战略”,自然会有好的效果。

第五人不仅能够让顾客满意,还能迎合顾客心理,自然就不会差。

第六人就已经达到了物我两重天的境界,不是在卖梳子,而是在卖护身符,把顾客的价值最大化,自然也就不足为奇了。

这是营销学不得不说的经典案例。从营销学我们可以得出“这个人不适合做销售”;“叩头营销”;“顾客满意战略”;“迎合心理”;“价值最大化”。

那么从产品角度是什么样的呢?和尚是没有头发的,这个大家都知道。那么如何在用户没有需求的情况下。把产品卖给用户?方法是,为目标用户创造需求

记得电影《华尔街之狼》有一个这样的场景,男猪脚和他的生意伙伴们在聚餐。男猪脚给他的其中一个伙伴扔了一支钢笔,并让他的伙伴秀一下,怎么把这支钢笔卖出去。

生意伙伴:“男猪脚,可以在餐巾纸上帮我签个名吗?”

男猪脚:“我没有笔呀!”

生意伙伴:“我有,卖给你。”

看懂了吗,一个营销高手并不是把用户与用户需求连接。而是在为用户创造需求。那么,其实也就可以把产品经理分成两类:一类是,把用户需求做到极致,代表人物:马化腾。另一类则是为用户创造出新需求,代表人物:乔布斯。

posted @ 2014-06-18 11:12 探路者 阅读(215) | 评论 (0)编辑 收藏

时间管理

人的一生两个最大的财富是:你的才华和你的时间。才华越来越多,但是时间越来越少,我们的一生可以说是用时间来换取才华。如果一天天过去了,我们的时间少了,而才华没有增加,那就是虚度了时光。所以,我们必须节省时间,有效率地使用时间。如何有效率地利用时间呢?我有下面几个建议:


1)做你真正感兴趣、与自己人生目标一致的事情。我发现我的“生产力”和我的“兴趣”有着直接的关系,而且这种关系还不是单纯的线性关系。如果面对我没有兴趣的事情,我可能会花掉40%的时间,但只能产生20%的效果;如果遇到我感兴趣的事情,我可能会花100%的时间而得到200%的效果。要在工作上奋发图强,身体健康固然重要,但是真正能改变你的状态的关键是心理而不是生理上的问题。真正地投入到你的工作中,你需要的是一种态度、一种渴望、一种意志。


2)知道你的时间是如何花掉的。挑一个星期,每天记录下每30分钟做的事情,然后做一个分类(例如:读书、准备GRE、和朋友聊天、社团活动等)和统计,看看自己什么方面花了太多的时间。凡事想要进步,必须先理解现状。每天结束后,把一整天做的事记下来,每15分钟为一个单位(例如:1:00—1:15等车,1:15—1:45搭车,1:45—2:45与朋友喝茶……)。在一周结束后,分析一下,这周你的时间如何可以更有效率地安排?有没有活动占太大的比例?有没有方法可以增加效率?


3)使用时间碎片和“死时间”。如果你做了上面的时间统计,你一定发现每天有很多时间流失掉了,例如等车、排队、走路、搭车等,可以用来背单字、打电话、温习功课等。现在随时随地都能上网,所以没有任何借口再发呆一次。我前一阵和同事一起出差,他们都很惊讶为什么我和他们整天在一起,但是我的电子邮件都可以及时回答?后来,他们发现,当他们在飞机上和汽车上聊天、读杂志和发呆的时候,我就把电子邮件全回了。重点是,无论自己忙还是不忙,你要把那些可以利用时间碎片做的事先准备好,到你有空闲的时候有计划地拿出来做。


4)要事为先 - 每天一大早挑出最重要的三件事,当天一定要能够做完。在工作和生活中每天都有干不完的事,唯一能够做的就是分清轻重缓急。要理解急事不等于重要的事情。每天除了办又急又重要的事情外,一定要注意不要成为急事的奴隶。有些急但是不重要的事情,你要学会放掉,要能对人说 no! 而且每天这三件事里最好有一件重要但是不急的,这样才能确保你没有成为急事的奴隶。


5)要有纪律。有的年轻人会说自己“没有时间学习”,其实,换个说法就是“学习没有被排上优先级次序”。曾经有一个教学生做时间管理的老师,他上课时带来两个大玻璃缸和一堆大小不一的石头。他做了一个实验,在其中一个玻璃缸中先把小石、砂倒进去,最后大石头就放不下了。而另一个玻璃缸中先放大石头,其它小石和砂却可以慢慢渗入。他以此为比喻说:“时间管理就是要找到自己的优先级,若颠倒顺序,一堆琐事占满了时间,重要的事情就没有空位了。”


6)运用80%—20%原则。人如果利用最高效的时间,只要20%的投入就能产生80%的效率。相对来说,如果使用最低效的时间,80%的时间投入只能产生20%效率。一天头脑最清楚的时候,应该放在最需要专心的工作上。与朋友、家人在一起的时间,相对来说,不需要头脑那么清楚。所以,我们要把握一天中20%的最高效时间(有些人是早晨,也有些人是下午和晚上;除了时间之外,还要看你的心态,血糖的高低,休息是否足够等综合考量),专门用于最困难的科目和最需要思考的学习上。许多同学喜欢熬夜,但是晚睡会伤身,所以还是尽量早睡早起。


7)平衡工作和家庭。我对于家庭的时间分配是用下列的原则:

    划清界限、言出必行——对家人做出承诺后,而且一定要做到,但是希望其他时间得到谅解。制定较低的期望值以免造成失望。

    忙中偷闲——不要一投入工作就忽视了家人,有时10分钟的体贴比10小时的陪伴还更受用。

    闲中偷忙——学会怎么利用时间碎片。例如:家人没起床的时候,你就可以利用这段空闲时间去做你需要的工作。

    注重有质量的时间(quality time)——时间不是每一分钟都是一样的,有时需要全神贯注,有时坐在旁边上网就可以了。要记得家人平时为你牺牲很多,度假、周末是你补偿的机会。

posted @ 2014-06-16 11:02 探路者 阅读(249) | 评论 (0)编辑 收藏

设计模式六大原则

1、单一职责原则(Single Responsibility Principle,简称SRP)
      单一职责原则,就一个类而言,应该仅有一个引起它变化的原因。如果一个类承担的职责过多,就等于把这些职责耦合在一起,一个职责的变化可能会消弱或者一直 这个类完成其他职责的能力。这种耦合会导致脆弱的设计,当变化发生时,设计会遭受到意想不到的破坏。而软件设计真正要做的许多内容,就是发现职责,并把这 些职责相互分离。


      一句话点评:高内聚低耦合的绝佳体现,不要乱拉关系,独善其身挺好。

 

2、 开放--封闭原则(The Open-Closed Principle简称OCP)
       开放--封闭原则,是说软件实体(类、模块、函数等等)应该可以扩展,但是不可以修改。即对于扩展是开放的,对于更改是封闭的。 我们不可能做到未卜先知,在设计的时候尽可能让一个类足够好,设计好了就不要去修改了;不能完全封闭的情况下,当发生变化时,我们就创建抽象来隔离以后发 生的同类变化。


      一句话点评:开放扩展,封闭更改,开合有度是一门艺术。

 

3、依赖倒转原则(Dependence Inversion Principle )
      依赖倒转原则,指高层模块不应该依赖低层模块,两个都应该依赖抽象;抽象不应该依赖细节,细节应该依赖抽象。说白了就是要针对接口编程,不要对实现编程。 举个例子:计算机硬件中,如果内存坏了,那么只需要换一个内存条就可以了,而不需要去换一个主板,在这里内存是一个接口类,只要符合他的规格要求就行,无 论是那一根。


     一句话点评:搞建筑时要做设计师,而不是砖瓦工,抽象的蓝图要靠具体的材料一点点实现。

 

4、里氏代换原则(Liskov Substitution Principle,简称LSP)
     里氏代换原则,子类型必须能够替换掉他们的父类型。在软件里面,把父类都替换成其子类,程序的行为不会发生变化。正是由于子类型的可替换性才使得使用父类型的模块在无需修改的情况下就可以扩展。


     一句话点评:长辈给了你继承的权利就一定要做赡养的义务,把长辈的职责都要承担起来。

 

5、迪米特法则(Law of Demeter
      迪米特法则,如 果两个类不必彼此直接通信,那么这两个类就不应当发生直接的相互作用。如果其中一个类需要调用另一个类的某一个方法时,可以通过第三者转发这个调用。类之 间的耦合越弱,就越有利于复用,一个处在弱耦合的类被修改,不会对有关系的类造成波及。 主要是强调了类之间的松耦合。


     一句话点评:不要和陌生人说话,若两国交战要尽量避免正面冲突,多派使者协商调度。

 

6、合成/聚合复用原则(Composition/Aggregation Principle],简称CARP)
     合成聚合复用原则,尽量使用合成/聚合,尽量不使用类继承。合成聚合是“has  a”的关系,而继承是“is  a”的关系。由于继承是一中强耦合的结构,父类变,子类必变。所以不是“is  a”关系,我们一般不要用继承。优先使用合成聚合复用原则,有助于保持每个类的封装,降低继承的层次。
     一句话点评:优生优育,不要盲目繁衍。

posted @ 2014-05-28 09:41 探路者 阅读(668) | 评论 (0)编辑 收藏

SCADA/EMS Developer

MN to design, develop, test, and deliver software components.
These components are integrated and delivered as part of the EMS/SCADA software solutions.
Help develop visualization software for the Energy industry.
Software will incorporate geo-spatial features and presentation of real-time data.
Will be working with Qt/C++ and interfacing with Java, Oracle, and several other technologies on both Windows and Linux.
Experience with multithreading and multi-tier software is highly desired.
Software developed will have an emphasis on security, reliability, and performance.
Should be able to pick up new technologies quickly.
Will be requested to diagnose and troubleshoot complex software problems.
Will work both internally with other software development teams and will also work with customer project teams.
Excellent communications skills required.
Up to 15% domestic and international travel is required.
Minimum Requirements:
BS in Computer Science, Computer Engineering, or a related discipline.
3 years of experience with SCADA/EMS software programming.
3 years of C++ programming experience.
2 years of Qt programming experience.
1 year of experience with Oracle or similar RDBMS.
Excellent communication skills.

posted @ 2014-03-19 11:12 探路者 阅读(618) | 评论 (1)编辑 收藏

Component Object Framework

   基于组件开发的模型有一下方案:
   1.微软的COM
   2.XPCOM 
   3.DBus
   4. DCOP
   5.OSGi

posted @ 2013-12-25 11:19 探路者 阅读(293) | 评论 (0)编辑 收藏

error C2471

error C2471: 无法更新程序数据库“d:/Work/ Project/FBReader/debug/vc90.pdb”

   fatal error C1083: 无法打开程序数据库文件:“d:/Work/ Project/FBReader/debug/vc90.pdb”: No such file or directory ..

解决方案:修改项目属性 右击项目 --> "属性”

1. “C/C++” --> "常规” -->”调试信息格式” 设置为 “C7 兼容(/Z7)”

2. “C/C++” --> "代码生成” -->”启用字符串池” 设置为 “是(/GF)”

3. “链接器” --> "调试” -->”生成调试信息” 设置为 “是(/DEBUG)”

如图:

0_1272007922DxD0

posted @ 2013-12-22 18:25 探路者 阅读(417) | 评论 (0)编辑 收藏

bjam 参数


典型的参数
bjam --toolset=msvc-8.0 --with-date_time --with-thread  --link=static --threading=multi --runtime-link=shared debug stage

为了方便,你还可以这样:

bjam --with-date_time --build-type=complete --toolset=msvc-8.0 stage

注意,--build-type=complete表示生成debug release static shared的各种版本

还有一个非常需要注意的地方,我在一次编译的时候遇见过很变态的问题,由于安装了VS2008,所以我想用VC9来编译,结果VC9的设置似乎与环境变量冲突,在打开命令行工具的时候会提示:此时不应有:<此处为系统的所有环境变量>。这个奇怪的问题很可能是由于环境变量里的路径过长或包含不该有的符号而导致的,但奇怪的是,VS2005并没有这个冲突问题。所以,这时候如果要编译boost的话只有两条路走:1、搞定VS2008的冲突,重装环境变量里路径过长的程序。2、用VS2005的命令行工具去编译。顺带一提的是,这时候最好不要用系统中的cmd,而是在开始->程序->VS2005->工具->命令提示里执行bjam的工作。

其他参考:

bjam参数 --build-dir=<builddir> 编译的临时文件会放在builddir里(这样比较好管理,编译完就可以把它删除了) 
--stagedir=<stagedir> 存放编译后库文件的路径,默认是stage 
--build-type=complete 编译所有版本,不然只会编译一小部分版本(确切地说是相当于:variant=release, threading=multi;link=shared|static;runtime-link=shared) 
variant=debug|release 决定编译什么版本(Debug or Release?) 
link=static|shared 决定使用静态库还是动态库。 
threading=single|multi 决定使用单线程还是多线程库。 
runtime-link=static|shared 决定是静态还是动态链接C/C++标准库。 
--with-<library> 只编译指定的库,如输入--with-regex就只编译regex库了。 
--show-libraries 显示需要编译的库名称

libboost_regex-vc71-mt-d-1_34.lib 为例:

·         lib 
前缀:除了Microsoft Windows之外,每一个Boost库的名字都以此字符串开始。在Windows上,只有普通的静态库使用lib前缀;导入库和DLL不使用。

·         boost_regex 
库名称:所有boost库名文件以boost_开头。

·         -vc71 
Toolset
标记:标识了构建该库所用的toolset和版本。

·         -mt 
Threading
标记:标识构建该库启用了多线程支持。不支持多线程的库没有-mt

·         -d 
ABI
标记:编码了影响库和其他编译代码交互的细节。对于每一种特性,向标记中添加一个字母: 

Key

Use this library when:

s

静态链接到C++标准库和编译器运行时支撑库

g

使用标准库和运行时支撑库的调试版本

y

使用Python的特殊调试构建

d

构建代码的调试版本

p

使用STLPort标准库而不是编译器提供的默认库

n

使用STLPort已被弃用的“native iostreams”

·         -1_34 
版本标记:完整的Boost发布号,下划线代替点。例如,1.31.1版本将被标记为“-1_31_1”

·         .lib 
扩展名:取决于操作系统。在大多数unix平台上,.a是静态库,.so是共享库。在Windows上,.dll表示共享库,.lib是静态或导入库。

 

下表是对Regex库编译后的文件名:

文件名

含义

编译使用该库的程序时应使用的编译选项

libboost_regex-vc90-mt-sgd-1_38.lib

静态库,多线程,调试版本 
使用静态调试版本C运行时库(LIBCMTD.LIBLIBCPMTD.LIB

/MTd

libboost_regex-vc90-mt-s-1_38.lib

静态库,多线程 
使用静态版本C运行时库(LIBCMT.LIBLIBCPMT.LIB

/MT

libboost_regex-vc90-mt-gd-1_38.lib

静态库,多线程,调试版本 
使用动态调试版本C运行时库(MSVCRTD.LIBMSVCPRTD.LIB

/MDd

libboost_regex-vc90-mt-1_38.lib

静态库,多线程 
使用动态版本C运行时库(MSVCRT.LIBMSVCPRT.LIB

/MD

boost_regex-vc90-mt-gd-1_38.lib

导入库(boost_regex-vc90-mt-gd-1_38.dll),多线程,调试版本

 

boost_regex-vc90-mt-1_38.lib

导入库(boost_regex-vc90-mt-1_38.dll)多线程

 

 

需要注意的是,链接时,所使用的Regex库文件名必须和编译选项匹配,否则会造成如下链接错误:

LINK : warning LNK4098: defaultlib '×××××' conflicts with use of other libs; use /NODEFAULTLIB:library

原因是,当编译时,cl.exe(也就是VC的编译器)会根据上述编译选项在编译成的obj文件中植入相应的defaultlib文件名(使用DUMPBIN /DIRECTIVE ***,lib可以查看),如/MT对应的就是LIBCMT.LIBC)和LIBCPMT.LIBC++标准库)。当链接器处理该obj文件时,会从文件中取出该defaultlib文件名,将其放在命令行库列表的最后以供使用。对于静态库的处理也是如此,静态库也是由一些obj文件组成的,每个obj文件中也根据当时的编译选项被植入了相应的defaultlib。当链接器处理静态库时,也会将涉及到的obj文件中的defaultlib放在命令行库列表的最后。假设,我们的程序使用/MT编译,那个对应的defaultlib就是LIBCMT.LIBC)和LIBCPMT.LIBC++标准库)。而使用的是libboost_regex-vc90-mt-sgd-1_38.lib,它对应的defaultlib就是LIBCMTD.LIBLIBCPMTD.LIB。链接过程中,链接器会发现采用了不同的运行时库,所以会出现上述错误。





posted @ 2013-12-14 10:36 探路者 阅读(1910) | 评论 (0)编辑 收藏

仅列出标题
共6页: 1 2 3 4 5 6 

导航

统计

常用链接

留言簿

随笔分类

随笔档案

文章分类

文章档案

新闻档案

Android

Compiler Course

VIM

编译技术集合

测试

高性能计算

个人博客

框架/组件/库

搜索

最新评论

阅读排行榜

评论排行榜