显示下一条  |  关闭

为着理想勇敢前进

 
 
 
 
 
 

怎样玩《跑跑龟》才能欺负人

2012-5-13 12:34:03 阅读27 评论0 132012/05 May13

怎样玩《跑跑龟》才能欺负人 - 杨博 - 为着理想勇敢前进

《跑跑龟》是个很简单的桌游。基本上接触过桌游的人都玩过吧。看上去《跑跑龟》没啥策略性,输赢也就看运气而已。这么想你就错了,跑跑龟其实是个浅度策略游戏,如果你按以下方式玩,胜率可以达到80%。(注:本文是按“同时到终点时上面的乌龟赢”的规则来写的)

  • 中前期没用的牌可以随便出,但有用的牌要留着。所有的牌按有用程度排序如下:
    1. 任意颜色乌龟前进两格
    2. 自己颜色乌龟前进两格
    3. 任意颜色乌龟前进一格
    4. 自己颜色乌龟前进一格
    5. 任意颜色乌龟后退一格
    6. 特定颜色乌龟后退一格
    7. 最后一名乌龟前进两格
    8. 其他颜色乌龟前进两格
    9. 最后一名乌龟前进一格
    10. 其他颜色乌龟前进一格
  • 怎样玩《跑跑龟》才能欺负人 - 杨博 - 为着理想勇敢前进自己颜色乌龟前进两格的牌很宝贵,前期一般不会用。如果前期有人用了前进两格的牌,那么他多半不是这种颜色的乌龟。
  • 在走完赛程一半之前,尽量要让自己的乌龟落后
  • 过了赛程一半之后,要尽力让自己乌龟踩住别的乌龟而不要被别的乌龟踩住。如果前期你单独落后,那么只要你前进就能踩住别人。如果你被别的乌龟踩住,你就让自己头顶的乌龟前进或后退而把自己露出来。
  • 如果对方乌龟移到了只剩最后两步的位置,一定要用自己的乌龟压上去。最好不要单独压上去,而是让自己脚下的乌龟驼着自己压上去。如果没有办法把自己的乌龟压上去,就用后退牌让对方乌龟退回来。
  • 轮到你行动时,如果只剩两格了而自己的乌龟在顶上,那么用你先前憋的好牌冲线吧。

作者  | 2012-5-13 12:34:03 | 阅读(27) |评论(0) | 阅读全文>>

简单还是复杂?

2012-4-25 20:16:54 阅读51 评论0 252012/04 Apr25

作者:Martin Odersky

译者:杨博

原文:Simple or Complicated ? 

最近我们在激烈讨论,有的说Scala对正常程序员来说很复杂,有的说Scala其实是一门编码很简单的语言。有两个帖子在讨论(http://michid.wordpress.com/http://warpedjavaguy.wordpress.com/2010/08/02/the-scala-is-too-complex-conspiracy-1/)后面的回帖也值得一看。 
看了这些帖子和回帖后,我觉得很多人没讲到一块,完全是鸡同鸭讲嘛。所以我想举例说明这个问题不像表面上看的这么简单。 

 

简单还是复杂? - 杨博 - 为着理想勇敢前进                 简单还是复杂? - 杨博 - 为着理想勇敢前进

哪边更简单?

造哪个更简单?显然是前者。 
用起来更简单的呢?取决于……哼哼哼。如果你没用过键盘,也没用过电话,你可能觉得学莫尔斯电码还容易点。但我们其他人肯定觉得智能手机更简单啊。 
和别的语言比,Scala更像智能手机而非莫尔斯电报机。Scala编译期和核心标准库本身是极其复杂的软件,但用户体验却自由又友好。我有证据证明Scala真心易用。瞧瞧基于Scala的Kojo(http://netbeans.dzone.com/learn-scala-with-kojo),是教小屁孩初学编程用的。再说印度有上百名高中女生从Scala开始学编程(http://www.himjyotischool.org/)。这就是证据啊,即使不是名校博士生或者超级牛人之类的普通人也能上手嘛。 
你可以说这样比不公平。智能手机和莫尔斯电报机都是硬梆梆的硬件,编程语言却很开放,更像可以拼起来的玩具套装而非消费品。 
好,那我们就看看可以拼起来的玩具套装。  

简单还是复杂? - 杨博 - 为着理想勇敢前进           简单还是复杂? - 杨博 - 为着理想勇敢前进

哪边更简单? 

 

左边的摩比世界的形状种类要比右边的乐高多,所以你可能觉得乐高简单些。 
另一方面,对搭积木这件事来说,摩比世界提供的是固定的方案,而乐高则提供了近乎无限的选择。某些人有选择恐惧症(患病的不一定是他们本人,也可以是他们的同事)。对他们来说,摩比世界比乐高简单。 
Scala更像乐高而非摩比世界。从客观指标看,Scala的概念并不多,还算简单。比如咱们可以比比各种语言的关键字数量(http://carlosqt.blogspot.com/2010/07/how-many-keywords-do-you-type-in-your.html)。我自己从头比了比上下文无关语法的数量,Scala相当紧凑,和Haskell或OCaml相当,比Java5稍少,比C#和C++少得多。 
(Scala作为一种语言,的确比图灵机或Lambda演算复杂,但后两者就相当于程序语言中的莫尔斯电码。Scala也比Python、Scheme或者Clojure复杂,但Scala有完备的静态类型系统,不可避免的增大了语言的开销)。 
从另一角度看,因为Scala的许多概念都很通用很正交,所以能以各种方式组合起来。所以毫无疑问Scala为完成几乎所有任务都提供了多种方式供选。这就要求通过实践找出比其他方式更好的最佳方案。因而也要求你必须接受,有时达到好的设计会存在不止一条途径。 
你对这些比较可能仍然怀有不满,因为不管怎么说,几乎所有的编程语言都图灵完备,所以在这个层面上,每种语言都能实现其他所有语言的功能。而摩比世界可并不完备,至少摩比世界造不出寿司大餐。 
那么我们用乐高和乐高比,要得不? 

简单还是复杂? - 杨博 - 为着理想勇敢前进            简单还是复杂? - 杨博 - 为着理想勇敢前进

哪边更简单?


左边的乐高得宝系列显然比右边的乐高科技系列简单,没错吧? 
没错,但如果给你个任务让你造一个比较特别的东西,你用哪个系列?可能用得宝系列你也能造出来,但一定比用科技系列别扭。更有可能你需要用到得宝系列中根本没有的积木(比如绳状或胶状积木)。 
现在你该猜中了 :-) Scala更像科技系列而非得宝系列。相比别的语言,Scala能引导我们更简洁的解决问题。Scala还可以进行依赖注入(http://jonasboner.com/2008/10/06/real-world-scala-dependency-injection-di.html),而别的语言则需要引入外部配置文件才能做到。 
显然,这意味着Scala每行代码干的活更多,所以你会提出Scala比那些代码冗长的语言更难理解。但有实验证明(http://infoscience.epfl.ch/record/138586)事实并非如此,最终程序员会更适应紧凑的代码而非冗长的代码。 
我希望我能让你相信,“简单还是复杂”的辩论本身就不简单。复杂度是个多维的矢量。在一场讨论中,水友们笔下的“复杂度”往往是指复杂度不同维度上的分量。

作者  | 2012-4-25 20:16:54 | 阅读(51) |评论(0) | 阅读全文>>

尼玛Java真是太灵活了

2012-3-3 23:54:16 阅读78 评论1 32012/03 Mar3

我想知道Java程序打日志有多少种方式配置,于是画了一个图:

尼玛Java真是太灵活了 - 杨博

尼玛Java真是太灵活了!!!!!!!

作者  | 2012-3-3 23:54:16 | 阅读(78) |评论(1) | 阅读全文>>

大量new临时对象可以是一种优化手段

2012-2-29 8:24:23 阅读268 评论5 292012/02 Feb29

有C++经验的人往往知道,频繁在堆上分配对象对性能伤害很大。比如这样的代码就不是好代码:

void foo(int[] a) {
WrappedArray* wrappedArray = new WrappedArray(a);
wrappedArray->bar();
delete wrappedArray;
}

然而在JVM(指HotSpot虚拟机)上完全不是这样的。尽管JVM不提供显式在栈上创建对象的功能,但JVM会自动通过逃逸分析找出生命周期在函数范围内的临时对象,然后运行时优化这个函数,把对象创建放到栈上。逃逸分析在JRE7里面已经默认开启了,对临时对象多的代码效果很大。

Scala的隐式类型转换特性很鼓励创建临时对象。标准库中就有大量的隐式转换,会生成许多临时对象,如WrappedArrayStringAddWithFilter等。我读标准库的源码时甚至感到他们已经把创建临时对象当成一种优化手段了。

比如C++常见的pimpl模式往往会让用户代码持有一个包装对象的指针,包装对象的内部有一个底层实现对象的指针。这种做法在Scala里面就完全不被主张,而更鼓励长期持有底层对象,而在需要用时再临时包装成对外接口。

Scala的Array对应Java中的数组,功能很少,但Array可以隐式转换为功能全面的ArrayOps,使用ArrayOps上的函数时会生成多个临时对象。试看如下代码:

val myArray = Array("foo", "bar", "baz")
for (element <- myArray if element.contains('a')) { println(element) }

Scala编译器会把上述代码转换成这样:

val myArray: Array[String] = Array.apply("foo", "bar", "baz")
new (new ArrayOps[String](myArray)).WithFilter(
new AbstractFunction1[String, Boolean] {
override def apply(element: String): Boolean = {
return new StringOps(element).contains('a')
}
}).foreach(new AbstractFunction1[String, Unit] {
override def apply(element: String) {
println(element)
}
})

颤抖吧骚年,这一小段代码中居然有五处new,创建了ArrayOps[String]ArrayOps[String]#WithFilterAbstractFunction1[String, Boolean]StringOpsAbstractFunction1[String, Unit]整整五个临时对象。

Scala宁愿创建这么多临时对象也不用pimp模式是因为pimpl模式比直接持有底层对象多保存一个包装对象。如果在容器中保存大量包装对象时,额外的内存开销就会多起来,而pimp模式还会导致每次函数调用也多一次间接寻址的开销。另一方面,只持有底层对象的话,虽然原则上每次使用都会生成临时对象,但是这些临时对象经过JVM的逃逸分析、标量替换和内联优化后是零开销的。

但临时对象的开销取决于JVM的优化,然而JVM要在运行时优化,而且只有频繁运行的代码才会被优化。所以如果一个程序创建很多临时对象,那么刚启动时它的性能会很差,而运行一段时间后会慢慢变好。这也是为什么我们经常会感觉Java程序启动慢的原因之一。

作者  | 2012-2-29 8:24:23 | 阅读(268) |评论(5) | 阅读全文>>

印第安人质疑中国小学课文

2012-2-5 13:35:56 阅读140 评论2 52012/02 Feb5

印第安人质疑中国小学课文 - 杨博 - 为着理想勇敢前进

我小学时有一篇课文说讲了个故事,大意是

  1. 人的头盖骨很坚硬
  2. 生命生长的力量更大,只要把种子塞到头盖骨里面让种子发芽,头盖骨就被撑开了

我觉得这是胡扯嘛,同样是生命生长的力量,女人裹小脚时怎么没听说过撑破裹脚布的?

再说,按课文的意思,头盖骨如此坚硬,生命生长的力量如此大,那么可以推论,头盖骨生长的力量应该是世界上最大的力量了吧。于是印第安人就用自己的头做实验,用木板夹一夹,看看世界上最大的力量能否顶穿木板。

后来他们发现了真相:顶不穿的……

为了纪念他们为科学献身的精神,他们被称为扁头族(Flathead)

作者  | 2012-2-5 13:35:56 | 阅读(140) |评论(2) | 阅读全文>>

狮身人面像的逆袭,圆周率=5.1961524227...

2012-1-30 22:39:42 阅读262 评论2 302012/01 Jan30

最近有反华势力在造谣说π=4。笑死人了,圆周率怎么可能是整数?圆周率分明是“三倍根号三”好不好?
真相:圆周率=5.1961524227... - 杨博 - 为着理想勇敢前进
我是圆周率
只有掌握了正确的圆周率5.1961524227,才能建造出宏伟的狮身人面像和金字塔。

作者  | 2012-1-30 22:39:42 | 阅读(262) |评论(2) | 阅读全文>>

只有资深网页设计师才能看懂的笑话

2012-1-27 22:06:38 阅读163 评论0 272012/01 Jan27

刚看了第五季第14集生活大爆炸,上面提到海地和列支敦斯登参加1936年奥运会的时候,发现两国国旗相同。

于是,为了避免冲突,他们回国以后就开始着手把各自的国徽加到国旗上。

列支敦斯登人画了一个网页,在CSS中设置background-image为原来的国旗,然后找了个PNG格式的列支敦斯登国徽素材,做了个<img>标签把国徽放了进去。最后用谷歌浏览器打开这个网页,按Ctrl+P把网页打印出来,就去参加下一届奥运会了。

海地人也画了一个网页,在CSS中设置background-image为原来的国旗,然后也找了个PNG格式的海地国徽素材,做了个<img>标签把国徽放了进去。最后用Internet Explorer 6打开这个网页,按Ctrl+P把网页打印出来,就去参加下一届奥运会了。

后来他们又在下一届奥运会中碰面了。以下是他们的新国旗:

冷笑话一则 - 杨博 - 为着理想勇敢前进 冷笑话一则 - 杨博 - 为着理想勇敢前进
列支敦斯登的新国旗海地的新国旗

列支敦斯登看到海地的国旗就笑了:“小样儿,用IE6的吧?”

海地:“靠!这你都知道?”

列支敦斯登两手一摊:“用IE6也就罢了,连科比都不知道就敢参加奥运会?”

作者  | 2012-1-27 22:06:38 | 阅读(163) |评论(0) | 阅读全文>>

脏厕所技巧 之 开桌游吧的黑暗英雄

2012-1-26 6:48:08 阅读616 评论0 262012/01 Jan26

在即将迎来我参与的第一个专业店铺 —— 一家开在21楼的桌游吧 —— 开业一周年时,我还只是个刚下海的新手。那就像坐过山车一样令人兴奋。内容全部整合好了,而且游戏看起来很棒。只有一个问题:卫生间使用量超出了预计。

因为大部分卫生间都是被xu-xu和poo-poo用掉的,所以我们和店长一起删减零食供应以节省xu-xu次数。我们缩小零食份量,大量删除饮料,压缩咖啡浓度。有些做法店长可以接受,有些就只能推倒店长才得以实行了。

我们删了一个又一个,经过几天艰苦的努力,我们抵达了某种临界 —— 再也没有什么可以删的了。除非我们砍掉游戏的一些主体内容,不然再没有任何办法可以削减卫生间使用量了。我们精疲力尽地统计了当前的卫生间用量,发现还是多出150人次!

这时,我们这里最有经验的合伙人之一 —— 一个曾在“美好的久远年代”混迹开发领域数年的前辈 —— 决定接手这件事。他把我叫进他的办公室,我心想又要来一场劳心伤神的卫生间争夺战了吧。

可是,他只是走到一个包厢然后指着其中一堵墙,上面写着:

I am the bone of my sword.
Steel is my body, and fire is my blood.
I have created over a thousand blades.
Unknown to death, nor known to life.
Have withstood pain to create many weapons.
Yet, those hands will never hold anything.
So as I pray,
Unlimited Blade Works...

说,“看到了吗?”然后轻轻一按,推开了这面墙。搞定!

也许是察觉到我眼中的震撼,他向我解释说他在装修的早期阶段封印了这个卫生间。经验告诉他删减xu-xu到预计卫生间之内总是非常重要的,很多桌游吧因此几近失败。所以现在,作为一种常规做法,他总是留一个小卫生间,到真正需要的时候再释放它。

他走出办公室,然后宣布他已经把卫生间使用量减至上限之内,后来他被看作是这个桌游吧的英雄。

尽管被这种野蛮的做法“震惊了”,我还是不得不承认我对他的做法很感兴趣。我还没想到在哪里可以用上这招,但我知道了在有些时候,当你面对障碍时,为了应对困境而事先藏起一些卫生间真的非常有意义。时间和经验带来的改变可真是有趣。


写程序的黑暗英雄致敬。

作者  | 2012-1-26 6:48:08 | 阅读(616) |评论(0) | 阅读全文>>

网络论战和囚徒困境

2012-1-21 1:18:48 阅读91 评论0 212012/01 Jan21

今天看了看韩寒和方舟子的论战,这不就是囚徒困境吗?

想象一下可能发生的各种情况:

  韩寒沉默韩寒开骂
方舟子沉默
方舟子平安无事声望 +0
韩寒平安无事声望 +0

方舟子被韩寒的粉丝用铁锤击杀声望 -2
韩寒赢得冰冰的芳心 抱得美人归
树立“堂堂正正,光明磊落”的形象
声望 +1
方舟子开骂
方舟子又揭露了一桩丑闻声望 +1
韩寒背上“有团队”的坏名声声望 -2
方舟子被各种讽刺挖苦声望 -1
韩寒被抓到“改错别字”的把柄声望 -1

在网络论战这种囚徒困境中,韩寒和方舟子两人的最优决策都是对抗到底,最终必定导致两败俱伤的结果。

作者  | 2012-1-21 1:18:48 | 阅读(91) |评论(0) | 阅读全文>>

傻子才搞游行示威

2011-12-24 1:42:50 阅读186 评论0 242011/12 Dec24

近来发生了一件悲剧。某村村民因为一些合法诉求搞了两次游行示威,游行过程中难免有点暴力行为。官府事后算账,拘留了几个村民,其中一个村民被拘留死了。

如果理解游行示威的意义,这样的悲剧就不会发生了。 游行示威的意义并非向外界展示力量。若要向外界展示力量的话,集体签字或拍集体照就够了。 游行示威的意义在于让参与者产生激情,给参与者洗脑,提高参与者的凝聚力。

然而,游行示威并非洗脑的最佳做法。如果有合法的集体诉求,最佳手段是办法律讲座。法律讲座要低调的办。地点应选择很大的室内场地。人数是多多益善,把能通知到的人都叫上。

法律讲座的要点是讲诉求涉及的相关法条和诉讼流程,引导观众齐声朗读相关条文,就像疯狂英语那样干。 在中华人民共和国境内朗读中华人民共和国的法律,总不能说是颠覆国家安全的行为吧。最好一开场就全场朗读三遍《刑法》第一百零五条第二款,给参与者壮胆。 除此之外。还要讲类似诉求的成功案例(在案例汇编的书上找,书店里面多的是)。讲案例是为了鼓励观众,让观众觉得中国是讲法律的,自己站在法律有利的一方,给观众信心。

做法律讲座之前必须备好课,规划好兴趣曲线。还要事先私下通知少量核心成员当托,以在讲座时调动场上气氛。

讲座结束前,观众整整齐齐排一个方阵,拉出诉求的横幅,拍张照。一定要排整齐有气势,不要搞行为艺术,也不要学毕业照那种摆法。散会后,大家把学到知识用上,遵守法律走法律流程。拍好的照片需要精心设计,配合煽情的文案,写成一篇催人泪下图文并茂的文章,然后放到网上,发动集体疯狂转载。如果在网上流传得当,会给当局一些社会压力,迫使他们遵守法律不耍流氓。

法律讲座既合法,又安全,还提高了集体凝聚力,社会影响力也并不差,比游行示威强多了。连搞传销的人都懂得这个道理,天天办讲座。只有比信传销的傻子还蠢的人才游行示威,还瓜兮兮的跑去公安局登记。

作者  | 2011-12-24 1:42:50 | 阅读(186) |评论(0) | 阅读全文>>

我曾经也用Google Code,直到我的膝盖中了一箭……

2011-12-12 8:23:05 阅读272 评论0 122011/12 Dec12

github有Fork功能,Google Code一样有Clone功能。但是github上的项目比Google Code上的项目社区更活跃,Google Code上大家普遍懒得自己Clone、Hack并贡献补丁。为什么?

这是因为二者的界面设计不同。

github一个项目的首页内容主要就三样:仓库地址、源代码目录、README(内容通常是编译指南),你要是不去点右边大大的Fork按钮你都觉得不好意思。

再比较一下导航条:

  • github: Code | Network | Pull Requests | Issues | Wiki | Stats & Graphs 
  • Google Code: Project Home | Downloads | Wiki | Issues | Source

看到没有,github功能的顺序基本上和Google Code是颠倒的。至于Downloads这种让用户不劳而获的栏目,github才不要有呢。

作者  | 2011-12-12 8:23:05 | 阅读(272) |评论(0) | 阅读全文>>

如果我来设计Maven

2011-12-7 21:35:34 阅读279 评论5 72011/12 Dec7

Maven有三大死穴
  1. 不灵活。尽管Maven本身已经包罗万象拥有了很多功能,但想要增加点自定义的编译时干的事情,就很麻烦。你必须另外建立一个Maven插件项目,然后用Java写一坨插件代码,最后再到另一个项目中去引用那个插件项目,把插件的执行注入到构建的某个步骤中。哪怕你想干的事情只是简单的一句 echo yyy=$XXX > xxx.ini,你都得写个插件。
  2. 依赖的库难以修改。尽管Maven提供了开源的仓库,但你使用他们的方式却是下载二进制包,这实在太不给力,如果你发现别人的东西有bug要修复,那你改了之后那个依赖的库就有两个版本,一个是官方版本,一个是你的修改版本,你就得hack你本地的Maven库缓存让他用你的修改版本,一旦官方版本更新,你就又要蛋疼了。
  3. 太慢,除了依赖于网速要下载大量东西以外,本身执行速度也很慢。
这三大死穴都有更好的设计来解决。可是搞Java的人品味都有问题,所以搞出这么难用的东西。如果我来设计Maven,这三个问题都很好解决

  • 第一个问题只要不用xml格式做配置文件,而把配置文件格式换成某种图灵完备语言,用这种语言本身作为DSL即可. 比如maven的替代产品buildr、sbt的配置文件格式分别是JRuby、Scala。在buildr、sbt中如果想定制编译时操作,直接用那种语言写就得了。顺便插一句,尽管shell也是图灵完备语言,但太弱,所以make也有类似的问题。
  • 第二个问题其实这年头分布式版本管理系统已经解决得很好了。公共仓库和本地缓存应该都换成git或mercurial,不要傻逼兮兮的用什么HTTP。然后仓库里面要放源码,方便用户自己hack. 这区别就好像Debian和Gentoo的区别一样。(PS: 大家用Maven或者Debian的时候,发现别人写的代码有问题,自己改好了还得装孙子求着别人合并回主干啊,有木有有木有!!)(继续PS: 话说遇到Github上的项目就不用装孙子,俺自己Fork出来改改改改改,改好了给你丢个Pull Request,你爱接受不接受!!霸气有木有!!!)
  • 第三个问题分为两部分解决。
    1. 网速问题,改用git或mercurial的协议之后就可以大大改善了。
    2. 本身执行速度慢,这是因为Java加载速度太慢,加载类时的文件IO极为可观,此外再加上Java虚拟机JIT还有些开销。尽管对一个长久运行的进程来说启动慢一点没有关系,但对于构建管理这种一个进程只存活几秒钟的应用来说,启动慢就不能忍了。其实如果要用JVM语言做构建系统,不应该每次执行都启动一个Java进程,而应该做成守护进程,每次执行只启动一个客户端来戳一下守护进程。守护进程和客户端进程之间通讯协议用ssh就好了嘛。 守护进程用Scala或者Java编写,客户端就不用写了,用openssh就行。人家openssh是C写的,启动速度超快。
以上三个死穴,就是Maven的开发者自己听了,也得点头称是,而无法反驳。但对这糟糕设计的解读,则因人而异。在我看来,Maven处处违背“提供机制,而不是策略”的设计准则,藐视用户智商,把用户人为划分成插件开发者和普通用户,才是导致错误设计的内在原因。这种错误是路线错误,Maven选择了迎合白痴而得罪黑客,必将被世人唾弃。

作者  | 2011-12-7 21:35:34 | 阅读(279) |评论(5) | 阅读全文>>

打一句log时间不到一纳秒!完爆log4j、logback、slf4j……

2011-11-23 4:14:42 阅读377 评论3 232011/11 Nov23

用Java打log时,最不爽的一点就是即使你把log禁用了,只要打log的那行代码还在,每次执行到那一行还是有开销!尼玛Java没有宏啊,不能像C++那样做个编译选项不输出log时就直接跳过嘛。况且就算Java有宏,搞Java那帮道貌暗忍的人渣们也不会用的,他们只用XML和Annotation 来配置,感受不到编译选项带来的爱。Scala就有个-Xelide-below的编译选项可以排除掉不需要的函数调用,直接被搞Lift的混蛋们无视了,照样用着天杀的slf4j.

那么用slf4j打log到底有多大开销呢?这取决于slf4j的后端,不管用什么后端,真正输出log是需要IO的,一般都要几十上百微妙,也就是几万或者几十万纳秒,这部分开销是省不了的。我刚才抱怨的是那些被过滤掉的log,这些log的开销根据参数的复杂程度,要消耗从几个纳秒到上百个纳秒不等。

纳秒什么的最讨厌了,上百个纳秒,听起来好多!我一个纳秒都不想浪费!于是我就写了个pico-logger,pico-logger对org.slf4j.Logger包装了一下,但用pico-logger比直接用org.slf4j.Logger快得多。

如果一条log没被过滤掉,需要实际IO输出,用pico-logger和用slf4j一样快。但是slf4j打一条复杂log时,即使被过滤掉了,也需要消耗上百纳秒,而pico-logger过滤掉log时一纳秒都不浪费。无论多复杂的log,pico-logger在JVM优化后执行时间都不超过2个时钟周期,在我2.1GHz的CPU上只要952皮秒,一纳秒都不到。如果传给pico-logger的参数是没有额外变量的字符串字面量,执行时间为零。零执行时间的意思是你在任何深层循环输出log,只要一禁用掉,都对性能完全没有影响。

以下是在Scala中PicoLogger的用法:

object Foo extends PicoLogger(org.slf4j.LoggerFactory.getLogger(classOf[Foo]))
{
def foo() {
// 用PicoLogger,当trace级别被禁用时,零执行时间
trace("string literal")

// 用org.slf4j.Logger,当trace级别被禁用时,消耗4纳秒左右。不同后端性能稍有差异。
logger.trace("string literal")
}

def bar(p1: Int, p2: Double, p3: Long, p4: Byte, p5: Boolean) {
// 用PicoLogger,当trace级别被禁用时,2个时钟周期,在2GHz以上的CPU时不到1纳秒
trace("p1=" + p1 + ", p2=" + p2 + ", p3=" + p3 + ", p4=" + p4 + ", p5=" + p5)

// 用org.slf4j.Logger,当trace级别被禁用时,消耗约100纳秒
logger.trace("p1={},p2={},p3={},p4={},p5={}", Array(p1, p2, p3, p4, p5))
}
}

顺便做了个benchmark,对比了一下slf4j和pico-logger的性能。在下列表格中,每一项的单位是时钟周期,即以java -server方式运行,并经过充分优化后执行需要消耗的CPU时钟周期。在我2.1GHz的CPU上,每个时钟周期是0.476纳秒,即476皮秒。与slf4j中用格式化字符串的代码对应的pico-logger用例是拼接字符串。

字符串字面量字符串格式+2个字符串参数字符串格式+2个整数参数字符串格式+5个各种参数
slf4j+log4j151641+186+
slf4j+logback9939+191+
slf4j+java.util.logging6734+187+
pico-logger02

slf4j整数参数会变慢,是因为slf4j需要为非引用的参数装箱。每次装箱就要消耗大约20个时钟周期,因为装箱涉及内存分配,所以每次装箱消耗的时钟周期数不等。上述表格中的数字都是取最好的结果,实际上平均成绩还会比这个最好成绩消耗更多的CPU时间。字符串字面量下面的“0”表示如果输出的这条log会被过滤掉,那么哪怕连写10遍,JVM优化后都是直接跳过这些代码的压根不作任何判断。

代码我放Google Code上了:http://pico-logger.googlecode.com/,一共只有一个类,性能评测的代码也在里面。

作者  | 2011-11-23 4:14:42 | 阅读(377) |评论(3) | 阅读全文>>

Java7的异步IO 赞+1

2011-11-5 4:29:51 阅读199 评论0 52011/11 Nov5

Java7的异步IO是多年以前就期待的东西了,居然拖了这么多年才正式发布。理论上说aio这样的Proactor模型的缓冲区直接由内核填充,可以比epoll这样的Reactor模型省一次内存复制,性能会更好些。但实际上Java处理一遍数据消耗的时间远远超过缓冲区的一次规整复制,所以实际上在Linux上应该看不出和nio相比的改善。当然,在Windows中新的异步IO用“完成端口”实现,和nio的实现WSAEventSelect比那是快得多了。

新的异步IO另一意义在于其API是事件的,用户能方便的编写CPS风格代码。而nio的话,除非用上netty、mina这样笨重的框架,不然用户自己写Selector神马的,还得多写几百行乏味的代码。(PS: mina和netty的作者都是同一个,代码绕来绕去,封装得也不好,API超复杂,我很不喜欢该设计。)

新的异步IO最后的好处是为各种PC操作系统提供了统一的覆盖网络和磁盘IO的高性能API,不论是服务器还是客户端编程都能使用。这也算是这几年操作系统API逐渐完善的一个标志吧。Windows方面,完成端口在Windows 9x中是没有的。Windows 2000有完成端口,但是网络方面支持不完备,仅仅只有收发两个函数支持,accept和connect都是Windows XP和Windows Server 2003中逐渐加入的。Linux方面则是2.6的某个版本才加入了,记得与epoll似乎是同一年放出来的(但开发者普遍都习惯用select/poll,更容易转到epoll上,所以没什么人用aio)。

其实我一直觉得电驴、BT和迅雷之类的软件应该要用完成端口来读写文件会比较好。完成端口除了不阻塞提交任务的线程以外,还不占用磁盘缓存,对系统的内存管理压力小,不会莫名其妙拖慢系统。电驴、BT分享文件的时候,本来内置了分块功能,只要分块和硬盘簇对齐,应用程序自己缓存就够了。

作者  | 2011-11-5 4:29:51 | 阅读(199) |评论(0) | 阅读全文>>

“少生孩子多养猪”毁灭ACG产业

2011-10-24 18:49:07 阅读143 评论1 242011/10 Oct24

什么产品的人均产量和人口成正比?答案是知识产权。

考虑一个国家有100人,其中有百分之十是作家,就一共有10位作家。假设每个作家每年写一本书,这个国家每人都买每一本书来看,那么每部书都能卖100本,而这个国家的每个人每年能看10本书。假设每本书版税收入100元,那么每个作家收入10000元。这个国家的GDP中,由知识产权贡献的GDP就是100000元。

而另一个国家有200人,其中有百分之十是作家,就一共有20位作家。假设每个作家每年写一本书,这个国家人都买每一本书来看,那么每部书都能卖200本,而这个国家的每个人每年能看20本书。假设每本书版税收入100元,那么每个作家收入20000元。这个国家的GDP中,由知识产权贡献的GDP就是400000元。

以上的分析是理想情况,现实中会更复杂。比如,每个人看书的总需求是有限的。但现实中的情况仍然符合这些原理,作家可以联合起来写更高质量的书,即使平均每个读者看书的数量不变,质量也会提高,相当于间接提高了需求。

在IT行业(尤其是游戏行业),能感觉到生在中国的巨大优势。一个好网络游戏在中国的在线人数往往比世界上任何一个国家都多。

夸张点讲,假如中国没有计划生育,总人口比现在多20%,青少年人口比现在高50%,那么梦幻西游的在线人数就会比现实中的情况多50%,为网易贡献的收入也要高50%,然而网易需要为这些收入支付的营销成本和开发成本增幅却远不到50%,最终导致网易在没有计划生育的中国能比现实中的中国利润增加超过50%.

宅男腐女们,要问中国ACG事业为何如此落后,就因为你爹妈只生了你一个。

作者  | 2011-10-24 18:49:07 | 阅读(143) |评论(1) | 阅读全文>>

查看所有日志>>

 
 
 
 
 

自定义模块

 
 
模块内容加载中...
 
 
 
 
 
 
 
 

广东省 深圳市 双鱼座

 发消息  写留言

 
博客等级加载中...
今日访问加载中...
总访问量加载中...
最后登录加载中...
 
 
 
 
 
 
 
日志评论
评论列表加载中...
 
 
 
 
 
 我要留言
 
 
 
留言列表加载中...
 
 
 
 
 

自定义模块

 
 
模块内容加载中...
 
 
 
 
 
 
 
模块内容加载中...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2012

   
创建博客 登录  
 关注