posts - 11, comments - 9, trackbacks - 0, articles - 0
  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

2012年7月29日

原来Markdown如此之方便,github又提供了page服务,还能用上git,真是无法无天了!

http://www.100hack.com

或者
http://cuixin.github.com

posted @ 2013-06-29 01:30 steven.cui 阅读(228) | 评论 (0)编辑 收藏

第5章 调试你的大脑


我从来都不想成为怪人,但别人都认为我想。

——弗兰克.扎帕,美国作曲家、音乐家、电影导演


直觉是伟大的, 除了当它不伟大的时候。

我们必须直视自己,“调试”(debug)自己的大脑。

关于debugging,可以自己扩展阅读,软件是有人创造的,错误难免。

为什么这么说呢?人类大脑又不是开源软件,没法找到代码去修正,只是展示出错的地方,但你却能知道自己的缺陷在哪里,只能尽量避免,却几乎难以修正。这就是人,而不是计算机:

     1.认知偏见:思维如何被误导

     2.时代影响:同代人如何影响你

     3.个性倾向:个性如何影响思维

     4.硬件故障:大脑较老区域如何压制较聪明的区域


了解认知偏见

     Wikipedia列举了大约90多种认知偏见,书中着重举了几个值得重视的偏见:

   思维定势

     思维定势(Thinking Set) 是由先前的活动而造成的一种对活动的特殊的心理准备状态,或活动的倾向性。在环境不变的条件下,定势使人能够应用已掌握的方法迅速解决问题。而在情境发生变化时,它则会妨碍人采用新的方法。消极的思维定势是束缚创造性思维的枷锁。

   基本归因错误

     归因理论的一个现象,即人们常常把他人的行为归因于人格或态度等内在特质上,而忽略他们所处情境的重要性。比如,尽管我们在评价他人的行为时有充分的证据支持,但我们总是倾向于低估外部因素的影响,而高估内部或个人因素的影响。这种现象解释了当销售人员的业绩不佳时,销售经理更倾向于将其归因于下属的懒惰而不是竞争对手的实力。

  基本归因错误(fundamental attribution error,FAE)描绘人们在考察某些行为或后果的原因时高估倾向性因素(谴责或赞誉人)、低估情境性因素(谴责或赞誉环境)的双重倾向。

   自私的偏见

     这种偏见使人们相信,项目的成功是我的功劳,失败则与我无关。这种行为可能是一种个人防御机制导致的,但是请记住你也是系统的一部分——无论结果好与坏。

    需要定论

     我们对疑问和不确定性感到不舒服,我们会竭尽全力解决不确定性。其实不确定性有时候是件好事,选择是开放的。如果强行把不确定的事情强行的定论,会迫使你选择放弃,易于犯错,例如你宣布了一项项目截止日期,并没有能力移除内在的不确定性,它只是一种自我掩饰。说到这里,我们常说靠谱还是不靠谱,我个人是比较烦不靠谱的人,而我爱人却总结出,不靠谱的人有时候往往做朋友比靠谱的人好相处,而且有时候能帮到你。

     因为不靠谱的人在事情模棱两可的时候就可以承诺,但你别太把承诺当回事,也许他看似不靠谱的事情,真的就能办到。因为靠谱的人从来不做没把握的事情,不敢于尝试,不去争取尝试甚至,特别觉得一旦说出去的话就得全部做到,要不就只字未提,听她说完,身边的朋友的确,虽然有些看似不靠谱的,却真心对待的朋友,他们不是不靠谱,而是敢于给你帮助。


    认可上的偏见

     每个人都根据自己的成见和喜好原则来选择相应的事实。

    曝光效应

     会因为习惯和熟悉某种事物对其偏爱,这包括不在好用或者出错的工具或者技术。

     霍桑效应/宣泄效应

     1)社会心理学家所说的“霍桑效应”也就是所谓“宣泄效应”。霍桑工厂是美国西部电器公司的一家分厂。为了提高工作效率,这个厂请来包括心理学家在内的各种专家,在约两年的时间内找工人谈话两万余人次,耐心听取工人对管理的意见和抱怨,让他们尽情地宣泄出来。结果,霍桑厂的工作效率大大提高。这种奇妙的现象就被称作“霍桑效应”。

     2)1924年11月,以哈佛大学心理专家梅奥为首的研究小组进驻西屋(威斯汀豪斯)电气公司的霍桑工厂,他们的初衷是试图通过改善工作条件与环境等外在因素,找到提高劳动生产率的途径。他们选定了继电器车间的六名女工作为观察对象。在七个阶段的试验中,支持人不断改变照明、工资、休息时间、午餐、环境等因素,希望能发现这些因素和生产率的关系——这是传统管理理论所坚持的观点。但是很遗憾,不管外在因素怎么改变,试验组的生产来效率一直未上升。

     历时九年的实验和研究,学者们终于意识到了人不仅仅受到外在因素的刺激,更有自身主观上的激励,从而诞生了管理行为理论。就霍桑试验本身来看,当这六个女工被抽出来成为一组的时候,她们就意识到了自己是特殊的群体,是试验的对象,是这些专家一直关心的对象,这种受注意的感觉使得她们加倍努力工作,以证明自己是优秀的,是值得关注的。

     有一所国外的学校,在入学的时候会对每个学生进行智力测试,以智力测验的结果将学生分为优秀班和普通班。结果有一次在例行检查时发现,一年之前入学的一批学生的测验结果由于某种失误被颠倒了,也就是说现在的优秀班其实是普通的孩子,而真正聪明的孩子却在普通班。但是这一年的课程成绩却如同往年一样,优秀班明显高于普通班,并未出现异常。原本普通的孩子被当作优等生关注,他们自己也就认为自己是优秀的,额外的关注加上心理暗示使得丑小鸭真的成了白天鹅。

     实验结论

  1. 改变工作条件和劳动效率之间没有直接的因果关系;
  2. 提高生产效率的决定因素是员工情绪,而不是工作条件;
  3. 关心员工的情感和员工的不满情绪,有助于提高劳动生产率。

研究者认为,这种自然形成的非正式组织(群体),它的职能,对内在于控制其成员的行为,对外则为了保护其成员,使之不受来自管理阶层的干预。这种非正式的组织一般都存在着自然形成的领袖人物。至于它形成的原因,并不完全取决于经济的发展,主要是与更大的社会组织相联系。

霍桑实验最初的研究是探讨一系列控制条件(薪水、车间照明度、湿度、休息间隔,等)对员工工作表现的影响。研究中意外发现,各种试验处理对生产效率都有促进作用,甚至当控制条件回归初始状态时,促进作用仍然存在。这一现象发生在每一名受试验者身上,对于受试验者整体而言,促进作用的结论亦为真。

很显然,实验假设的各项条件并非是唯一的或决定性的生产效率影响因素。对此,乔治·埃尔顿·梅奥George Elton Mayo)以及他的助手们所做的解释是,受试者对于新的实验处理会产生正向反应,即由于环境改变(试验者的出现)而改变行为。所以绩效的提高,并非由实验操控造成。这种效果就是我们所称的“霍桑效应”或“霍索恩效应”(Hawthorne Effect)。

     霍桑效应的优点

  • 能够清楚地发现员工关心的事项。
  • 如果模型建设适当、准确的话,它所给出的解决生产力的办法具有长期的、可持续的特点。
  • 对员工工作条件进行持续性衡量评估,有助于管理者指定长期的战略决策。

     霍桑效应的缺点

  • 一些内在的工作环境属性难以辨识,如组织动力。
  • 生产力模型的参数选择a、b、c比较主观,取决于管理人员的个人认识。
  • 关键性的工作环境属性是动态的,模型需要不断调整反映现实情况。
  • 从总体上来看,生产力模型的准确度与管理人员的个人判断力、敏锐性紧密相关。

     霍桑效应的启示

     “霍桑效应”,也就是社会心理学所说的“宣泄效应”,它给我们的启示是:人在生产或者生活的过程中,对自己未能实现和不能满足的情绪,要把它发泄出来,情绪的发泄对人的身心健康和工作效率都非常有利。

    虚假记忆(让我想到一部片子《罗生门》)

     虚假记忆(pseudo memory)是大脑记忆的信息之间自动的组合导致不真实的回忆。每个人的大脑都可能产生虚假的记忆,或将事物的真实情况扭曲。人们会对自己的记忆坚信不疑,甚至会对大脑编造的谎言信以为真。这并非一种发病过程。所有人都会产生虚假记忆”,特别是关于童年时期亲身经历的场景的记忆。

     符号约简谬论和名词谬论

     移位给事物贴上个标签就意味着理解或者能解释它,例如:当你尝试画一只人手时,L型思维的人会把光线、阴影、纹理的负责性简化为“五条线加一个棍”。就如同人们一直认为天鹅只能是白的。

在这里本人强烈推荐《怪诞心理学》,《影响力》,《引爆点》,《乌合之众》等等,关于心理方面的书籍,每个人都应该读点心理学,不是在于说自己脑子有问题,每个人都是有心理偏差的,正因为心理偏差造成的个体不同,才有各种不同的性格,社会进步的重要标志是能包容各种形式的不同形态存在。

心理偏差是你的个性也好性格也罢,敢于去了解别人和自己本身就是一种对自己思维的挑战,或许说你再向自己发出改变的挑战,也许习惯是最难改变的,我们看似对新鲜事物充满好奇,但如果熟悉一种事物,却很难接受和改变自己替换原有思维。

如果说中国古代皇帝最有作为的——李世民,如果只是但从人心理角度出发分析,对与其“元认知”的能力让其能把国建建设的如此强大——自我批判和自我重塑,而这份能力恰恰是管理者最需要的能力。

预言的失败

     做预言太困难了,特别是关于未来的预测。

                                                ——瑜伽.贝拉,伟大的智者、哲学家兼棒球手

     符号约简(请注意:不是符号简约,这两个字前后颠倒,却意思相差万里)是个非常有害的问题,看个例子,你在尝试画一只人手时,L型把光线、阴影、纹理的复杂性简化为“五条线加一个棍”。这种简化被认为把复杂的现实看做由基本原素的组成:柏拉图立体。

     我们善于将复杂的东西进行简化和抽象,并且计算机编程也是如此之思想,但会让我们陷入误区。

     以前从来没有人认为有黑天鹅的存在,以至于科学界认为没有黑天鹅,知道有一只黑天鹅真的出现了。没发现不等于不存在,很少也不代表没有。

     作为一个团队,我们往往会错过重要的发展,因为我们关注了错误的事情或者提了错误的问题。

     现在,还有人在讨论学习java好还是.net好?N年前的各种争吵:RMI还是CORBA能取得中间件的胜利?Windows还是Linux能赢得桌面的胜利?

     就像是WEB的发展让这些问题毫无意义,Web是典型的黑天鹅,其出乎意料的改变了游戏规则。


“很少“不意味着”没有“

     2012,7.21北京据说60年一遇的暴雨,几乎每年都喊。程序员在写程序的时候,不可能出现这样的bug啊,其实应该说概率低,但不代表没有这种情况发生,花时间查一下认为的不可能的事情吧。不要说:”绝不可能“!


推迟下结论

     软件的制作过程在我本人看来就是一个消除不确定性的过程,而且跟时间成正比,如下图所示:

     到项目末尾时你会达到智力巅峰,而在项目开始时则是最无知的。

     顶住压力。你会做出决策,事情会解决,只不过不是今天。

     适应不确定性,适应敏捷开发,尽可能的用更灵活的技术适应不确定性,适应了不确定性也就等于提高了效率。


难以回忆

     记忆是靠不住的,旧的记忆会随着时间改变,这反而会是你以为某些误解和偏见是对的,不要仅仅依赖你的记忆。中国有句谚语说得好:好记性不如烂笔头。


认清时代的影响

     在这章里作者给出了美国从1901到现在经历的几个时代,从技术和人的思维的变化,相似年龄段的人对某种事物的开发更接近,也就是不同年龄层次的人有代沟。本人不再赘述作者讲述的美国各年代的历史,其实这是我们都难以去逾越的,要想避免你所处时代的特有偏见,最好的方法就是保持多样性。承认一种事物的存在,但却能淡定的确很难。


了解个性倾向

     他人即地狱。

          ——让.保罗.萨特,法国思想家、作家、存在主义哲学

     尊重不同人的不同性格,当你跟别人争辩时,请想一想这点。

     MBTI(Myers Briggs Type Indicator)性格评估测试,在国内有些机构可以做些专业评测,如果想找免费的,可以借助谷歌去找,但如果英文一般的同学想做这个测试,我建议你去百合网,虽然是个婚恋网站,但这个MBTI还是比较专业哦,不过MBTI的测试结果就如同你自己的性格一样,性格有些人会发生改变,但有些人可能一辈子难以改变,曾经我做过测试,经历过几年后的测试有个界限发生了改变,所以不要让MBTI成为你潜意识的引导,而是作为了解自己的途径,但不要太过于相信,而是时常打破自己的”符号约简“。


找出硬件问题

     大脑常犯一些低级错误——硬件问题。

     我曾见看过各种报到,为了一个误会能让人失去理智。。。

     蜥蜴逻辑:

          战斗、逃跑或者恐惧

          立刻行动,不加思考

          领头意识,随意指使你的队友

          守卫领土,不分享信息和秘诀

          受到伤害,愤愤不平,让所有人都知道这是不公平的

          像我这样==好,不像我这样==不好

     你或许认识到以上几点我们都有过呢?

     见样学样,近朱者赤,近墨者黑,情绪就像传染病,常跟一些乐观的人在一起你也就变得乐观了。

     进化行为:当你开始重播这些喜欢的电影时,努力阻止自己,记住:这只是一部电影。

     心灵是自己的地方,在那里可以把地狱变成天堂,也可以把天堂变成地狱。

                                                                                               ——约翰.米尔顿《失乐园》


现在我不知道该思考什么

     在上几章提过,直觉是一种强大的工具,是专家的标志。但直觉可能完全错误,我们认为“正常的”未必是正常的。除了各种偏见,你可能被你自己误导,认为一切都好。

     之前提到关于创造一个R型到L型的转化,也就是说,思考时是全局性和经验性的,然后转换成更常规的实践和技能,从而实现学习过程。

     相信直觉,但是要验证。


最后,测试你自己

     当你坚信某种事情时,问问自己原因。

     尝试问问自己以下问题:

          你怎么知道的?

          谁说的?

          有什么特别的?

          我的做法会如何影响你?

          与什么或者谁比较?

          这总是发生么?你能想到一个特例么?

          如果你这样做了(或者不这样做)会怎么样?

          什么阻止了你?

     实践:

     当发生冲突时,考虑基本性格类型、不同年代的价值观、你的偏见、别人的偏见和情境。通过司考更多因素,是不是更容易解决冲突?

     仔细检查你的立场。你是如何知道你所知道的?什么使你这样认为?


     我们通过逻辑来证明,通过直觉去发现。

                                             ——庞加莱

 

posted @ 2012-08-13 01:38 steven.cui 阅读(364) | 评论 (0)编辑 收藏

原文请参考,如有问题和歧义请指正,谢谢:)

http://clojure.org/vars

变量和全局环境

Clojure是个很实用的语言,偶尔需要将维护和改变数据的值。她提供了4种不同的方式来操作变量:Vars, Refs, Agents, 和Atoms。Vars机制是是指向一个可改变的数据的位置,你可以为每个线程动态的绑定(制定一个新的存储位置)一个新值。Vars可以初始化根绑定(不是必须的),绑定的值对于所有线程都是共享的,但却别的线程就不能重新绑定。因此,要么Var可以为每个线程绑定值,要么使用根绑定。

下面的special form def 创建了一个Var,如果Var不存在和没有给初始化,var就是不绑定的(不允许创建非动态的Var,必须显式指定根绑定):

user=> (def x)
#'user/x
user=> x
java.lang.IllegalStateException: Var user/x is unbound.

为根值初始化(如果存在,就被再次绑定)

user=> (def x 1)
#'user/x
user=> x
1
 

默认情况下(定义的时候初始化了根绑定),Vars是静态的(static),但是,建立动态Var的定义可以通过元数据标记的方式,然后在线程用时通过binding来指定。

user=> (def ^:dynamic x 1)

user=> (def ^:dynamic y 1)

user=> (+ x y)

2

user=> (binding [x 2 y 3]

         (+ x y))

5

user=> (+ x y)

2

 

binding被创建后其他线程是是不可见的。创建的binding可以被赋值,也就是在没有离开调用堆栈之前可以被上下文访问。可以在一块代码之前设置matadata标签:dynamic来指定:

user=> (def ^:dynamic x 1)

#'user/x

user=> (meta #'x)

{:ns #<Namespace user>, :name x, :dynamic true, :line 30, :file "NO_SOURCE_PATH"}

user=> (binding [x 2] (println x))

2

nil

user=> x

1

user=>

 

如果你想让函数编译为static的,并且指定返回值,可以看下面的例子(速度提升不少,关键的调用函数可以采用这种方式加速):

 (defn fib [n]   (if (<= n 1)

    1

    (+ (fib (dec n)) (fib (- n 2)))))

#'user/fib

 (defn ^:static fib2 ^long [^long n]

  (if (<= n 1)

    1

    (+ (fib2 (dec n)) (fib2 (- n 2)))))

#'user/fib2

user=> (time (fib 38))

"Elapsed time: 1831.113 msecs"

63245986

user=> (time (fib2 38))

"Elapsed time: 328.715 msecs"

63245986

user=> (meta (var fib))

{:arglists ([n]), :ns #<Namespace user>, :name fib, :line 1, :file "NO_SOURCE_PATH"}

user=> (meta (var fib2))

{:arglists ([n]), :ns #<Namespace user>, :name fib2, :static true, :line 4, :file "NO_SOURCE_PATH"}

user=>

 

在上下文中可能需要重定义静态变量,从Clojure1.3开始提供with-redefswith-redefs-fn这两个宏来修改。

定义函数的defn也是Vars的存储方式,也可以在运行时被重定义。这也为aop编程带来很多方便,例如:你可以封装一个类似logging函数给调用的上下文或者或者线程。

 

(set! var-symbol expr)

将Vars指定为special form

当地一个操作符为symbol的时候,它必须是全局变量。当前线程绑定的值就是后面的expr,也就是说必须是Thread-local的才可以,否则将会抛出一个使用set!来设定根绑定变量的错误。变量的表达式expr必须有返回值。

注意,你不能赋值给一个函数的参数或者本地绑定,只能是java的字段Vars Refs和Agents,因为这些数据在Clojure里可不变的。

使用set为java字段设置值,可以查看 Java Interop.

 

Interning

命名空间维护了每个Var对象的全局符号映射。如果使用def定义变量没有在当前的命名空间找到该符号,就创建一个,否则使用现有的。创建或者寻找的过程被称作interning。这就意味着,除非Var对象取消映射,否则Var对象每次被查询,所以请在循环中千万不要引用Var的全局变量,否则将非常慢,通过let或者binding让全局变量取消映射来提高速度。命名空间在Evaluation中构建了全局环境,编译器也把所有free symbols当做Vars来解析了。

可以使用阅读宏(Reader)#’来得到Var对象的内部的值。

 

Non-interned的类型的变量

可以通过with-local-vars来创建non-interned类型的变量,在free symbol解析的时候将不会被发现,这些值只能被手工的访问,但是也可以用作当前线程的变量。

user=> (defn factorial [x]

         (with-local-vars [acc 1, cnt x]

           (while (> @cnt 0)

             (var-set acc (* @acc @cnt))

             (var-set cnt (dec @cnt)))

           @acc))

#'user/factorial

user=> (factorial 7)

5040

posted @ 2012-07-31 01:48 steven.cui 阅读(1477) | 评论 (0)编辑 收藏

原文章写在Google Groups thread里,但是还是值得再说下。

有朋友把Java和Clojure的一些代码片段放在Clojure Google group里比较,并提到Java的性能要比Clojure快太多了,疑问到底Clojure能不能赶上Java?

在我的一个开源项目clj-starcraft中,关于java的性能问题,实际上也是我始终面对的,在我写这篇文章的时,我的Clojure代码还是慢了Java代码6倍(Clojure花了70秒解析了1050个文件,Java则只有12秒)

然而,70秒对过去的速度而言不算太糟糕,在刚开始的时候,竟然花了10分钟来分析1050个文件。甚至比我用Python实现的还要慢。

感谢Java的profiler和热情的Clojure朋友,下面列出了我在提升Clojure性能方面的一些tips:


(set! *warn-on-reflection* true)

这恐怕是最重要的一个提升:打开这个设置将会警告你在任何一处用到Java反射API的方法和属性。如你所想,直接调用永远比反射要快,不管哪里Clojure都会你不能解析这个方法,你需要自己用type hint方式来避免反射调用。关于使用type hint,Clojure官方站点给了一个如何使用和提速的例子。

修复所有关于*warn-on-reflection* 的编译警告后,我的clj-starcraft从10分钟降到了3分半。


强制设置数据类型

Clojure可以使用Java的基础数据类型,无论何时在循环的时候,坚决考虑将你的值强制转换成基础类型,这将大幅提高你的性能。基础数据类型在Clojure官方网站有例子和如何进行强制转换来提高性能。


使用二元运算符

Clojure可以在一行里面支持多个表达式,但对于运算操作符,只有在两个的时候才被inlined,如果你发现自己的运算符已经超过了两个,或许该考虑重写你的代码让操作符显示的成为两个。下面请看两者之间的比较:

user> (time (dotimes [_ 1e7] (+ 2 4 5)))

"Elapsed time: 1200.703487 msecs"

user> (time (dotimes [_ 1e7] (+ 2 (+ 4 5))))

"Elapsed time: 241.716554 msecs"


使用==代替=

使用==比较数字来代替=,提升性能那是相当明显:

user> (time (dotimes [i 1e7] (= i i)))

"Elapsed time: 230.797482 msecs"

user> (time (dotimes [i 1e7] (== i i)))

"Elapsed time: 5.143681 msecs"


避免vectors的destructing binding

在一段循环种,如果你想为了提升可读性从vector中传出值,考虑下标访问来代替destructing binding。虽然代码看起来更清晰,但却非常慢。

user> (let [v [1 2 3]]

        (time

         (dotimes [_ 1e7]

           (let [[a b c] v]

             a b c))))

"Elapsed time: 537.239895 msecs"

user> (let [v [1 2 3]]

        (time

         (dotimes [_ 1e7]

           (let [a (v 0)

                 b (v 1)

                 c (v 2)]

             a b c))))

"Elapsed time: 12.072122 msecs"


优先使用本地变量

如果你需要在循环中查询一个值,你或许需要考虑使用本地变量(通过let定义)来代替全局变量。看下两者的时间对比:

user> (time

       (do

         (def x 1)

         (dotimes [_ 1e8]

           x)))

"Elapsed time: 372.373304 msecs"

user> (time

       (let [x 1]

         (dotimes [_ 1e8]

           x)))

"Elapsed time: 3.479041 msecs"

如果你想使用本地变量来提升性能,可以考虑下面比较土的式的方式来避免全局变量:

(let [local-x x]

  (defn my-fn [a b c]

    ...))

使用profiler工具:

JVM有两个profiler工具, -Xprof和-Xrunhprof,找到程序瓶颈而不是瞎猜。


最后说明:

你已经注意到,在这些性能提升中,通过调用百万量的执行来提升了几百毫秒的性能。所以,不到万不得已需要提升性能的时候,没必要让你的代码看起来不够清晰。

原文地址: http://gnuvince.wordpress.com/2009/05/11/clojure-performance-tips/

最后补充:可以通过指定编译为static方法来提高性能:

pasting

 

(defn
  ^{:static true}
  fib
  [n]
  (loop [a (long 1) b (long 1) i (long 1) r (list 1 1)]
    (if (== n i)
    r
    (recur b (+ a b) (inc i) (conj r (+ a b))))))

 

 

posted @ 2012-07-29 14:15 steven.cui 阅读(1928) | 评论 (2)编辑 收藏