存档

‘Computer Science’ 分类的存档

Safari 5.1不再支持本地PAC文件

2011年12月30日 没有评论

自把MacOS从SL升级到Lion后,Safari就不能使用pac文件了。

查了相关资料后发现原因是:Safari 5.1中修改沙箱环境的机制本地pac文件做代理已经不支持了,使用远程的就可以。例如http://开头的。

修改前:file://…,在Safari 5.1中已经失效

修改后:http://losthit.com/f/sshd.pac,可用。

该pac文件来自autoproxy,考虑到autoproxy使用的GAE有时会超过配额,或者撞墙导致无法使用。所以下载了一份自己保存,稍后做个脚本自动更新,当然还得加上校验。

参考链接:https://discussions.apple.com/message/15731770#15731770

分类: Computer Science, MacOS, 软件 标签: , ,

如何创建动态MOTD

2011年9月10日 没有评论

背景介绍

刚到淘宝时发现很多服务器登陆后都会显示一段AsciiArt的信息,觉得很好玩,也稍微有点用。如果你关心具体是什么,可以发送简历到jinxi.kj@taobao.com:)

如何显示静态MOTD

以上是背景,上网搜了一下,找到了相关的资料。其实很简单,只要修改了/etc/motd文件,登陆时就会被显示出来。如果需要增加颜色的话,可以参照这里的方法:“So You Like Color–The Mysterious ^[[ Characters" (http://www.linuxjournal.com/article/8603)。在vim中输入Ctrl+V后再按ESC,接下来写上颜色代码就行。有玩过term bbs的话应该会很熟悉。

如何显示动态MOTD

设置好/etc/motd后,马上就发现了一个问题,这是个静态的内容,自然就不能显示动态的信息。比如ip地址、硬盘占用、进程数等,除此之外,也没人喜欢部署多台机器时手动在motd中设置机器相关的参数,比如CPU、core数等。于是我就找到了这篇Blog: "HOWTO: Creating a Dynamic MOTD in Linux" (http://parkersamp.com/2010/10/howto-creating-a-dynamic-motd-in-linux/)。

具体方法很简单,编写一个脚本显示动态的motd,然后添加到/etc/profile中执行就行了。当然还需要禁用/etc/motd的显示。

如何禁用静态MOTD

修改: /etc/ssh/sshd_config
PrintMotd no
然后重启sshd: /etc/init.d/sshd restart or service sshd restart
更多信息参考上面提到的Blog。当然,最简单最暴力的方法是把/etc/motd文件中内容清空。

如何安装动态MOTD脚本

1. 将动态MOTD脚本放到某个目录下,比如/usr/local/bin/dynmotd。
2. 将脚本添加到/etc/profile中
修改: /etc/profile
/usr/local/bin/dynmotd

我自定义的Python脚本

由于前面我找到的Blog中使用的脚本是shell导致不方便修改,而且部分信息还是写死的;另一方面,Mac下面不能完全兼容。所以我自己用Python实现了一个类似的脚本,支持MacOS与Linux。考虑到不想把这个简单脚本搞得太复杂,所以没有用到兼容性、全面性更好地psutil。有兴趣的可以自己试试。

脚本可以到这里获取: https://github.com/chzealot/tools/tree/master/python/dynmotd

显示效果

MacOS(Darwin)下的显示效果

MacOS(Darwin)下的显示效果

Linux下的显示效果

Linux下的显示效果

Mongodb Beijing Conference 2011

2011年3月7日 2 条评论

上周四10gen在北京举办了Mongodb Beijing 2011,这半年里我也一直在生产环境使用Mongodb,对此还是很有兴趣的。特地过去听了几场收获还挺大的,在Blog里分享,也算是记录一下。

特别注明一下,我虽然一直在用Mongodb,但是仅关注其性能、方便,最重要的是方便地对单个document进行原子的findAndModify操作,反而对稳定性要求非常低,低到数据都不用备份的程度。因此,对于Mongodb的了解程度在会场人群中应该不算很高。

会议安排:上午先后有两场10gen工程师Roger和Alvin的演讲,下午分别是国内四位工程师分两个会场同时讲四个主题。

上午两场比较像Live Tutorial,对于我这种没有系统研究过的人来说还是蛮实用的。

第一场是Roger同学的Intro & Schema Design,从数据建模引入,重点还是在于通过Blog的案例,针对Document-Based数据库Schema Design,对比传统的关系型数据库,进行详细的分析,纯属教学性质的分享。特别说明的是,刚下载slides后发现有两个backup分别是DBRef和BSON,貌似大家都熟悉了,Q&A环节中没有用到。

第二场Alvin同学分享的是Replication and Sharding,同样是Tutorial性质的介绍。不过,对相应的机制及很可能遇到的隐患做了系统的说明,不得不说在讲解Replication Sets和Sharding机制时Slide动画做得干净、明了,貌似这点国人很少有兴趣去折腾。

总之,以上两场算是Mongodb官方分享,都只是系统性地做入门介绍。关于Replication Sets中Primary Member失效时Time Windows内仍然会有数据丢失风险,Alvin解释是需要getLastError,在应用层做处理;同样,Auto-Sharding也没有像官网提到的”without compromising functionality”。难怪有人评论没有说服力。

下午,分了两个会场同时进行,我选择了Yottaa那个实践分享的会场。这是一家刚成立一样的Startup,使用的技术和工具都比较新,这点很有意思。关于Mongodb的使用除了看Slide其他的也没什么好说的。在看到500G的数据,机器8G Memory时我就好奇问了一下性能问题,答案是Yottaa不太关心数据实时性。提问时有个插曲,我提到了500G数据文件load到内存时,大家都笑了,但是这不是我的问题,会后在微博我也解释了,Mongodb这类NoSQL基本还是将内存管理工作交给OS处理,所谓的LRU算法只不过是OS处理虚拟内存是常见的一种方法而已。数据文件全部load到内存的说法没啥错误,这点官网也有明确的解释:Mongodb.org: Caching – Memory Mapped Storage Engine

关于我提的数据量问题,会后在微博上也有童鞋很Nice地继续解释了一下:新浪微博评论。对于数据实时性以前可能我还不在乎,但是经历酒店价格数据实时处理后(包括搜索结果页的实时性),对这个还是比较谨慎的:1) 4sq宕机教训证明了虚拟内存性能值得担忧;2) 自身教训来说数据实时性要求不高的结论慎重点比较好。3) 突然需要调整为实时响应最新的数据的话,改动还蛮大,特别是针对我们这种搜索引擎来说,相信看过twitter实时搜索技术介绍大概能了解。

由于临时有事回公司了,没看最后一场。唯一遗憾的是没有GridFS和Map/Reduce的专门介绍。

当条件不成立时,命题永真

2011年3月7日 没有评论

在数理逻辑课入门时老师就会讲到这个命题:P->Q,当条件P=False时,不论Q为True or False,命题永真(注意是命题永真,不是结论永真)[注:见Wikipedia: 真值表]。

很遗憾的是这门课程不是大家都学,也不是所有人都学会了,所以经常看到一下违背这个逻辑的事情。比如,仅仅只是假设,你的KPI(Key Performance Indicators,关键业绩指标)中有没有这样一条:当同事A与B打架时,你做了事情X可以得到基本分,做了事情Y可以得到超出期望分。其实按照特定企业文化、团队目标设定某些特定的KPI(再强调一下前面打架的例子仅仅是假设,实际上应该没有这么荒唐的指标吧)都很正常,关键在于假设不成立时,该项得分给了满分还是零分,或者提前调整该项指标。按照真值表,条件(即打架事件)不成立时,结论(即你采取的行动)不论如何,命题永真,该项得分应为满分,但实际操作时往往是0分,杯具了吧。

以上仅是引子,我想说的是,合理地制定以结果为导向KPI真的很重要。上面的例子中很显然非常消极被动,面对一个指标,只能有心无力,感兴趣的事情做好了反而没人关注。

以结果为导向主要原因有三方面。

  • 首先,结果导向能更有效的提高工程师的主动性,虽然也有其他方法去促使积极主动,但是绩效考核中的结果导向能起到一个很大的正向推动作用;

  • 其次,在一个年轻的工程师团队中,考核中结果导向的指标与团队的指标直接或间接关联,能使得团队成员,尤其是工程师,有更大的成就感;

  • 最后,通过结果导向的KPI,在提高积极性的同时,能让工程师更快的成长,不至于每个季度下来零碎的过程性指标完成不少,但是难有很好的成长。

目前,有些工程师,尤其是前端工程师可能更多地是被动响应产品经理大量零碎的需求,这样很难制定结果导向的绩效指标。

如果加重结果导向的绩效指标也是可行的。

  • 首先,产品经理将更多的精力用于用户行为分析等,并制定出高阶的产品改进需求。细化的需求主要由工程师提出,使得被动响应变成主动积极。这一点在Facebook用得比较极致,甚至产品经理提出的需求如果不能打动工程师,那么就很可能不会被采纳;

  • 其次,很多时候细化的产品需求背后涉及了大量的技术点,由工程师来细化需求,在产品改进与技术成本及代价上做出较好的平衡,尤其是展现层面的改进,前端工程师对页面元素、交互方式有更全面、深刻的认识。例如,产品经理在分析用户,研究产品后得出一个通过图片展现降低跳出率的想法,转交给工程师后,由工程师通过白板给出UI原型图并解释交互方式。这时,工程师可以根据自己的特长给出一个技术复杂(可能)但是效果很好的方案,反而由产品经理提出细化的方案的话要么很粗糙,要么实现起来极其复杂。需要强调的是,细化需求如果由产品经理提出,不管事后通过多么好的沟通、讨论过程,终究不如先由工程师分析的效果好,因为细化的过程可能涉及到架构层面,甚至项目风险等问题;

  • 第三,工程师不应当仅关注技术点,反而应当拿出一定的精力去理解产品,理解用户需求,以求得在小团队中充分发挥出每一个人的最大作用。我们已经被学上了十几年,好不容易从学校熬出来了,就不要再被工作给上了;不能像学校那样总感觉做的、学的没啥用。在一个商业公司,永远都是先有用户然后有产品最后有技术,不能最大化的服务于产品的技术都是扯淡。

面向结果的方式明显有很多好处:通过制定若干长期的目标,使得我们从每周,甚至每天,这种细分粒度的固定办公时间中解脱出来;员工成就感更高、成长更快;流失率更低;更强调结果,前提是个人目标应对应于团队的目标。

相比以上积极面来说,花些精力去克服这些负面影响还是值得的:难免有些工作很难做准确的效果评估;管理难度更大;有可能出现员工之间的竞争,如果没处理好的话,等等。

* 参考:Wikipedia: ROWE – Results Only Work Environment



注:审阅时看到“扯淡”两字觉得都不像是我写的,其实大多时候我都是可以通融和变通的,但不想再改动了,只是补充一点:以上看法只是我觉得可行,行得通,必要时可以甚至必须要变通,所以现实中与以上相反的观点很多时候我也是认同的。部分例子对观点仅作解释,不起到论证作用。

海盗分金问题分析与解决

2010年8月2日 1 条评论

海盗分金问题分析与解决

——Nim取子问题变形后的解决方案

全文下载链接:海盗分金问题分析与解决.pdf

Author: Zealot Ke(kejie[at]kuxun.cn)
Date: 2010/7/30

背景

强哥邮件发出一个题目

  1. 有5个海盗,特别的残忍,特别的聪明
  2. 他们抢了100个金币,要进行分配,每个人都想分配足够多的金币,他们寸步不让.分配顺序是:5号海盗->4号海盗…1号海盗,即是:先由5号海盗决定如何分配,若分配不均,5号被扔下海,4号海盗再决定如何分配,依次类推.
  3. 如果没有二分之一或以上的海盗同意,分配人将被其他人扔下大海.
  4. 假如你是5号海盗,你会如何分配金币.确保自己不会被扔下大海,而且让其他4个海盗心服口服.

定义问题

5号海盗必须按照上述规则,找出最优分配方案,否则将被其他人扔下大海。

当前状态

正确分配方案还没出来,必须尽快找出最优解。

分析

典型的nim取子问题的变形,采用倒推方式即可找到最优解。

制定解决方案

倒推方法如下所示

  1. 如果只有一个海盗,如何分配?
  2. 如果有两个海盗,如何分配?
  3. 如果有n个海盗,每个海盗至少需要几个人同意?找出n-1个海盗情况下的分配方案中,需要收买多少海盗?最低需要多少金币?

实现解决方案

倒推方法实现如下表所示,每一行表示一种人数情况下的分配方案,也即,最后一行给出5号海盗的分配方案。

分配方案倒推分析表

分配方案倒推分析表

注意:从表中可以看出聪明是大前提,当然残忍也是。nim取子游戏向来是君子游戏,没有这个前提的话,后面的海盗不按套路出牌就不可能有最优解。

标准化解决方案

从上表不难看出规律,也即,自己拿尽可能多的金币,同时保证后面的人依次分配0、1交错的金币数。规范化命题如下
*命题: 假设对于n个聪明、残忍的海盗(n≥1),抢了Gold个金币,要进行分配,每个人都想分配足够多的金币,他们寸步不让。分配顺序是:n号海盗->n-1号海盗…1号海盗,即是:先由n号海盗决定如何分配,若分配不均,n号被扔下海,n-1号海盗再决定如何分配,依次类推。在该规则下,n号海盗最佳分配方案应当如此(为简单,避免使用地板函数,按n为奇偶数分类讨论):
不妨假设ones为得到1个金币海盗数,zeros为得到0个金币的海盗数。

  1. 当n为奇数时,ones=zeros=(n-1)/2,分配方案为Gold-ones,0,1…0,1
  2. 当n为偶数时,ones=( n-2)/2,zeros=n/2,分配方案为Gold-ones,0,1…1,0

该命题从上述分析中的规律中得出,不是定理,更不是公理,作为标准化解决方案需要严格证明。

证明:
注释:使用跳跃数学归纳法证明,跳跃的step为2。
先证明n为奇数时命题是否成立。
当n=1时,显然该命题成立
假设当n=m(m>1)时命题成立,则分配方案为
Ones(m) = Zeros(m) = (m-1)/2
Proposal(m) = Gold-Ones(m),0,1,…,0,1
= Gold-(m-1)/2, 0, 1, …,0,1
当n=m+1时,显然命题成立,理由如下
Ones(m+1) = (m+1-2)/2=(m-1)/2,Zeros(m+1) = (m+1)/2
注意:a) m+1为偶数,计算ones和zeros需要换个公式b) 对比n=m情形,仅仅是多了个0。
Proposal(m+1) = Gold-Ones(m+1),0,1,…,0,1,0
= Gold-(m-1)/2, 0, 1, …,0,1,0
对比Ones(m),Ones(m+1),Zeros(m),Zeros(m+1)可以看出仅仅是在Proposal(m)序列后面添个0。这会导致Proposal(m+1)与Proposal(m)两个序列中,0、1交错序列刚好错位,对应金币分配方案中则为:m+1号海盗分配方案就是把Proposal(m)中没有得到金币的人每人给1个金币实现自己金币最大化,同时保证同意的人数大于等于2。
综上所述,当n为奇数时,该命题成立。
再证明n为偶数时命题是否成立。
当n=2时,命题成立(大于的最小偶数只能是2)
归纳方法同1。
综合1、2分析,该命题成立。
证毕。

该标准化解决方案用程序实现如下
说明:该程序考虑了金币数量远小于海盗数量时,最先出来分配的部分海盗都得喂鲨鱼去了。

$ cat nim.c
#include 

const int g_first = 2;
const int g_zero = 0;
const int g_one = 1;

int print_proposal(int *gold, int *pirate, int *ones, int *zeros, int *status) {
        int             ret = 1;
        int             number = 0;
        int             remain = *gold - *ones;
        if (*pirate <= 0) {
                printf(".\n");
                return 0;
        }
        if (remain <= 0) {
                number = 0;     /* not enough gold, killed by others, regenerate proposal */
                ret = 1;        /* conitnue */

                /* regenerate proposal */
                if (*pirate % 2 == 0) {
                        *ones = (*pirate - 2) / 2;
                        *zeros = *pirate / 2;
                } else {
                        *ones = *zeros = (*pirate - 1) / 2;
                }
        } else if (*status == g_one) {
                number = 1;
                *ones--;
                *status = g_zero;
        } else if (*status == g_zero) {
                number = 0;
                *zeros--;
                *status = g_one;
        } else {
                number = remain;
                *status = g_zero;
        }
        if (*status != g_first && *ones <= 0 && *zeros <= 0) {
                ret = 0;
        }

        printf("%d ", number);
        *pirate = *pirate - 1;

        return ret;
}

int main()
{
        int             gold;
        int             pirate;
        int             ones;
        int             zeros;
        int             temp;
        int             status;         /* process first, zero or one */
        printf("Please Enter gold and pirate number:\n");
        while (scanf("%d %d", &gold, &pirate) == 2) {
                if (pirate < 1 || gold < 1)
                        break;

                if (pirate % 2 == 0) {
                        ones = (pirate - 2) / 2;
                        zeros = pirate / 2;
                } else {
                        ones = zeros = (pirate - 1) / 2;
                }

                status = g_first;
                printf("Proposal(%d, %d) is: ", gold, pirate);
                temp = pirate;
                while (print_proposal(&gold, &temp, &ones, &zeros, &status))
                        ;
                if (pirate == 1)
                        printf(".\n");

                printf("\n");
                printf("Please Enter gold and pirate number:\n");
        }
        return 0;
}

程序运行结果如下所示

$ gcc nim.c -o nim
$ ./nim
Please Enter gold and pirate number:
100 1
Proposal(100, 1) is: 100 .

Please Enter gold and pirate number:
100 2
Proposal(100, 2) is: 100 0 .

Please Enter gold and pirate number:
100 3
Proposal(100, 3) is: 99 0 1 .

Please Enter gold and pirate number:
100 4
Proposal(100, 4) is: 99 0 1 0 .

Please Enter gold and pirate number:
100 5
Proposal(100, 5) is: 98 0 1 0 1 .

Please Enter gold and pirate number:
0

决定下一步

本问题到此为止,暂时没有下一步动作。

总结

这个结论告诉我们

  1. 最先掌握分配权的人,看似最危险,胆小的人可能会担心所有人都不支持你,你就只能下海去喂鲨鱼了。其实,他优先掌握了主动权,天下武功,唯快不破,掌握市场先机很重要。
  2. 越快越好,但不能快过了头。100个金币,1000个海盗的话,最先出来分配的人必然死掉。同样的,20年前搞酒店搜索,率先占据主动权,快得一塌糊涂那也没戏。

完。

粗略读完《深入理解计算机系统》

2010年7月13日 没有评论

书名:深入理解计算机系统(修订版)
英文名:Computer Systems A Programmer’s Perspective (简称CSAPP)
从英文名称就可以看出这是一本面向程序员的书籍。豆瓣上的链接:http://book.douban.com/subject/1230413/

这本书讲述的内容就像名称里说的那样,从程序员观点来研究和发掘计算机系统的架构和潜力,包括信息计算的基础理论,也包括大量硬件、体系结构、操作系统层的知识,并结合编程开发提供了相应的参考信息。是一本难得的好书。

从写作上来讲,这本书也非常不错。全书自底向上,从信息理论入手,逐步扩展到硬件、汇编、操作系统,网络编程,最后到应用软件层(以http server为例分析并发编程)。而开篇第一章就把整本书的脉络概括了,后面每一章都只不过是第一章每一小节的细化。因此,阅读起来全局把握上很轻松,而这也恰恰是非常关键的一点。

整本书非常厚,800多页,大而全,但终究是一本系统级的书,更深入的细节还是只有比较概念性的介绍。比如汇编程序,虚拟存储器管理,基于事件触发的并发网络编程等等。本书每一章都可以独立成书,深入分析。实际上,我们的大学四年中的教材基本上就是这样独立编排的。所以这本书可以算是一个系统性的参考,用于辅助在头脑中建立整机的意识。具体到某一个特定的领域,需要找更详细的资料阅读才能有更好的理解。

最后,书中的习题看上去非常不错,而且都有细致的答案供参考。受限于公交上阅读环境,没有仔细看这部分。以后可以研究研究。

不过限于书中知识点大而全,对cs专业的学生来说,更好的选择是大一买下来显摆,大二消遣,大三把玩,大四送给小师妹。不是这本书不够深入,只是我觉得相比四年的课程来讲,这本书中的内容在cs毕业生眼里是必须精通的,没必要放到毕业后再继续学习这些基础。现在看看这本书,我也只能后悔没早点买到。

哦,对了,书中开篇介绍了一些非常有意思的实验题,比正文有趣多了。

R61在linux/debian下安装madwifi无线驱动

2010年4月6日 没有评论

本文记录Thinkpad R61i在debian lenny下安装madwifi驱动程序,替代ath5k,实现无线上网。
主要参考:http://forum.ubuntu.org.cn/viewtopic.php?f=116&t=169205。
仅作为tp安装linux的备忘,欢迎评论。

1. 下载
   Download the latest madwifi snapshot. // Google it

2. 解压
   $ tar zxvf madwifi-hal-0.10.5.6-current.tar.gz

3. 编译安装madwifi // 首先通过apt安装编译环境
   $ sudo aptitude install build-essential linux-headers-$(uname -r)
   $ make
   $ sudo make install

4. 安装module
   $ sudo modprobe ath_pci

5. 使网卡每次开机时都加载, make it load every time you boot
   $ sudo vi /etc/modules
   添加一行,如下
     ath_pci

6. 重新启动机器
   $ sudo reboot

注释 && 备忘
1. 为保证生效,重启前确认已屏蔽ath5k(默认驱动程序有可能是这个)
   检查是否已安装ath5k
   $ lsmod |grep ath5k
   有,则添加到blacklist
   $ cat /etc/modprobe.d/blacklist.conf
     blacklist ath5k
2. 确认安装驱动是否成功
   $ lsmod | grep ath_pci
     ath_pci               201176  0
     wlan                  193392  5 wlan_wep,wlan_scan_sta,ath_rate_sample,ath_pci
     ath_hal               300768  3 ath_rate_sample,ath_pci
3. 硬件型号查看
   $ lspci |grep Ethernet
     00:19.0 Ethernet controller: Intel Corporation 82566MM Gigabit Network Connection (rev 03)
     03:00.0 Ethernet controller: Atheros Communications Inc. AR242x 802.11abg Wireless PCI Express Adapter (rev 01)
4. ath5k是madwifi替代品,除非ath5k下无法连接无线,不建议使用madwifi

单件模式:Singleton那些事

2010年3月1日 3 条评论

单件模式确保一个类只有一个实例,并提供一个全局的访问点。 –《Head First 设计模式》

有些时候,我们恰好需要这样一种设计,保证我们实例化的类在进程地址空间内只有一个实例,有了Singleton,一切似乎都简单明了,其实暗藏杀机。

1. C++实现Singleton模式简单示例

简单的C++实现示例代码

class Singleton {
    public:
        static Singleton* GetInstance(void) {
            if (Singleton::m_instance == NULL) {
                Singleton::m_instance = new Singleton();
            }
            return Singleton::m_instance;
        }
    private:
        static Singleton* m_instance;
        Singleton() {}
};

使用gtest测试,简单地测试一下每次调用GetInstance是否返回同一地址

#include 
#include 

#include 
using namespace std;
#define NEW_COUNT 4096

class Singleton {
    public:
        static Singleton* GetInstance(void) {
            if (Singleton::m_instance == NULL) {
                Singleton::m_instance = new Singleton();
            }
            return Singleton::m_instance;
        }
    private:
        static Singleton* m_instance;
        Singleton() {}
};

Singleton* Singleton::m_instance = NULL;

TEST(Singleton, sample) {
    Singleton* init_instance = Singleton::GetInstance();
    ASSERT_NE(init_instance, (Singleton*)NULL);

    Singleton* p = NULL;
    ASSERT_EQ(p, (Singleton*)NULL);

    for (int i = 0; i < NEW_COUNT; ++i) {
        p = Singleton::GetInstance();
        ASSERT_EQ(init_instance, p);
    }
}

int main(int argc, char **argv)
{
    ::testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}

测试结果显示没有问题:
$ ./singleton
[==========] Running 1 test from 1 test case.
[----------] Global test environment set-up.
[----------] 1 test from Singleton
[ RUN ] Singleton.sample
[ OK ] Singleton.sample (1 ms)
[----------] 1 test from Singleton (1 ms total)

[----------] Global test environment tear-down
[==========] 1 test from 1 test case ran. (2 ms total)
[ PASSED ] 1 test.

当然,这种测试没有太大意义。给出测试结果,主要用于之后的对比。

2. python程序中调用Singleton模式的C++代码
初次接触Singleton后发现,使用Singleton模式的C++代码融合到python中有意想不到的惊喜:如果有某个类初始化需要很长时间,而之后调用的速度都很快的话,使用Singleton模式,然后在python中多次调用时,不会出现重复的初始化操作。
简单地尝试了一下

首先在singleton.cpp中添加了一行输出,标识一次初始化操作:

Singleton* Singleton::GetInstance(void) {
    if (Singleton::m_instance == NULL) {
        Singleton::m_instance = new Singleton();
        std::cout << "initialize here." << std::endl;
    }
    return Singleton::m_instance;
}

封装的代码如下
$ cat _pysingleton.cpp -n

#include 

#include "singleton.h"

using namespace std;

PyObject * GetInstance(PyObject *self, PyObject *args) {
    Singleton::GetInstance();
    return Py_BuildValue("s", NULL);
}

static PyMethodDef _pysingletonMethods[] = {
    {"GetInstance", GetInstance, METH_VARARGS, "get instance."},
    {NULL, NULL},
};

PyMODINIT_FUNC init_pysingleton(void) {
    PyObject * m;
    m = Py_InitModule("_pysingleton", _pysingletonMethods);
}

编译出来共享库_pysingleton.so
$ cat Makefile -n

CC                =       g++
FLAGS           =       -ggdb -O2 -Wall
INC               =       -I/usr/include/python2.5
LIB               =       -lgtest -lpython2.5
LLIB              =

%.o:%.cpp
        $(CC) $(FLAGS) $(INC) -c $<

_pysingleton.so: singleton.o _pysingleton.o
        $(CC) -shared $(CFLAGS) $(LLIB) $(INCLUDE) $^ -o $@

clean:
        rm -f *.so
        rm -f *.o
        rm -f *.pyc
        rm -f singleton

写个简单的python脚本测试一下在单一进程空间里,是否真的只调用一次
$ cat pysingleton.py -n

#!/usr/bin/env python
# -*- coding: utf-8 -*-

''' sample for pysingleton
'''

import os
import sys
import _pysingleton

class PySingleton:
    def __init__(self):
        _pysingleton.GetInstance()

def main():
    ''' main function
    '''
    for i in xrange(3):
        PySingleton()
    print 'Done'

if __name__ == '__main__':
    main()

结果是
$ ./pysingleton.py
initialize here.
Done

3. 多线程中使用Singleton模式
多线程里就会遇到一个double-check问题 (double-check-lock problem, DCLP)
首先,静态变量m_instance作用域是全局的,处于临界区,在多线程需要加锁。这一点很好理解。
但是,简单的在if外面加锁势必会影响性能,毕竟只有第一次调用才会生效,每次都有一次锁操作太费时,也没必要。
于是,就会有double-check方法了,伪代码为
if (Singleton::m_instance == NULL) // first check
lock
if (Singleton::m_instance == NULL) // second check

从这里可以看出,double-check有效地避免了重复锁操作问题。
然而,问题还没有结束。采用double-check的话,又会引入另一个问题。在这里
Singleton::m_instance = new Singleton();
编译器可能会做个优化,首先将一个有效的内存地址返回给m_instance,然后再调用构造函数初始化。这样很有下一次double-check中首次检查通过,但是得到的内存地址指向的是一个未经初始化的类。后果怎么样,只有天知道了。
更多细节,参考这里:http://www.ibm.com/developerworks/library/j-dcl.html

a. 最简单的修改方法是
Singleton* temp = new Singleton();
m_instance = temp;

但是一个自作聪明地编译器还是会把结果优化成难以想象的样子
b. 另一个方法就是使用volatile关键字,用以声明不受编译器优化的影响
比如 Singleton* volatile temp = new Singleton();
但是远远不够,temp是volatile,但是*temp呢,temp->foo,temp->bar...这些成员呢?所以,要改的话,得把全世界都改成volatile,除了那个lock-_-|||

4. 以上都只考虑单核,再考虑一下多核机器,问题将会更加复杂

总结:珍爱生命,远离Singleton。尤其是不要把Singleton放进通用库中,还有C++中那个叫template的高级玩意儿,都搞在一起老天都很难保证会发生些什么。


1. 这里也在讨论单例模式Why Singletons Are Controversial
2. 代码托管到Google Code,欢迎围观、讨论、批评、挑bug:点此进入(http://code.google.com/p/zldemo/source/browse/#svn/trunk/blog/singleton_everything)
(墙内用户请不要使用https访问)

过度设计的典范: 新浪微博

2009年11月7日 没有评论

(我的登录名是chzealot[at]gmail.com)
以下功能除非特别说明,都是在win7下Maxthon中测试(IE v8)
1. 登录框的suggestion
首先,suggestion是为用户提供便利的,而且可以把记忆的负担从用户那里接手过来。但是新浪微博这个suggestion的目的我一直没看明白。很显然我的登录名排在suggestion的倒数第二,而排在前面的那些候选项中除了第一个外其他都不是有效的微博帐号。不知道新浪pm怎么想的,用一堆无效的登录名霸占了原本属于有效用户名的位置。可见这个suggestion要么就是拍脑袋拍出来的,要么就是pm能力有问题。
其次,有一个非功能性的bug,suggestion框与登录名的框没有对齐,大概有3个像素的差距。做出花哨的功能远没有查找细节的bug来的重要,显然在国内测试的重要性总是被人忽略(后面还会列出很多bug)。
最后,又是一个过度设计的问题,看看下图中的鼠标右下方,那个chzealot@sina.com的提示干啥用的?没有任何提示作用,反而遮住了第三个候选项。该设计的地方不去动脑筋想,却把精力投放在毫无意义的事情上。把最简单的事情做好就是基础,基础没做好就想往上盖房子只能苦了IT民工加班做无用功。

login suggestion

login suggestion

2. 登录框上提示输入密码的框
首先,没有与输入框对齐。
其次,也是最重要的一个bug,为什么“请输入密码”的提示框飘在登录名的输入框上方,难道让我在第一个输入框中输入密码吗?

提示:“请输入密码”

提示:“请输入密码”

3. 找回密码功能在chrome v4中无法使用
点击“找回密码”,进入http://login.sina.com.cn/cgi/getpwd/getpwd0.php?entry=sso,页面空白。
虽然chrome用户量少,可能不在考虑范围之内,但是这么简单的页面在chrome中显示为空白页在我看来太说不过去了。
4. 新浪微博不是微博
为什么呢?因为在新浪微博不是你在玩,而是你看别人玩,看名人玩,又是还要被新浪玩。看下图吧。
登录后就只能看到5条最新的消息,不知道是不是我笨,找了好半天也没找到怎么查看更多。从下图中,我只能感受到新浪大声呼喊:你丫赶紧去关注那些名人吃喝拉撒吧!

关注名人

关注名人

5. 搜索用户
这个输入框好复杂啊,搜完之后我才发现应该选择suggestion中第二个选项才能搜索人。
首先,搜索用户和搜索话题两个截然不同的东西硬塞在一起成何体统。
其次,这个suggestion的风格到处都在使用,给我留下的印象是候选项是具有相同属性和功能的并列元素,显然在这里不是。于是我刚学会用这个suggestion,不一会又迷糊了。简单啊,简单的在大部分情况下就是对的。
还有,校内网的右上角就是搜索用户,其他也有不少类似网站右上角用来搜索用户,为什么不遵守用户习惯呢。非得把搜索话题硬塞进来。
最后,那搜索话题放哪呢?这个一会就说。

搜索用户

搜索用户

6. 搜索话题
刚才说到了搜索用户功能兼了搜索话题功能,其实在同样页面上有个专门的话题搜索框,见下图。重复设计!
既然已经有了专门的话题搜索框,再把话题搜索塞到用户搜索里就难以接受了。简单啊,想法能不能简单点。

搜索话题

搜索话题

7. 我的好友在哪里
基本上所有社交网站都会在sidebar中给出好友列表,但是新浪微博没有。你只能在右侧看到“粉丝”,这个链接是你的好友,faint吧,兄弟们。
反而,新浪给出了大量与你无关的人,就是那些所谓的名人,其中大部人名人就是上来诉说自个的吃喝拉撒,毫无意义。

关注用户

关注用户

最后,总结一下,新浪blog就是名人写日记给粉丝看得,而且大部分名人的日记很流水很无聊。显然日记满足不了需求了,于是新浪推出微博,让这些名人上来把吃喝拉撒事情也能方便的给粉丝们交代了。
典型的小作坊作业,目光短浅,其实趁着twitter被盾,直接抄过来,多雇点编辑删帖,对上做好公关工作。做成中国的twitter后,总有一天那些所谓的名人自己就上来注册了,而且不会发无聊的东西,因为那时没人关注吃喝拉撒了。

Linux/Debian字体去掉锯齿的方法

2009年10月21日 没有评论

Linux/Debian字体去掉锯齿的方法

在台式机上装了个Debian,但不知道怎么设置字体清晰,网上找了很多方法,都不好使,一直都很模
糊地讲究着。不过把字号稍微设置大点就不模糊了,浏览网页和用terminal都没问题,只是菜单栏地
址栏什么的基本看不清楚。
今天突然上网搜了一下,看到这个词antialias,突然想起来我没改过这个。赶紧看看~/.fonts.conf
。果然,里面antialias设为false,这个应该是反锯齿选项,设为true:
<edit mode=”assign” name=”antialias” >
<bool>true</bool>
</edit>
然后ctrl+alt+backspace重启x,菜单栏小字体都清晰了,Great,哈哈:-)
上两张图

在台式机上装了个Debian,但不知道怎么设置字体清晰,网上找了很多方法,都不好使,一直都很模

糊地将就着。不过把字号稍微设置大点就不模糊了,浏览网页和用terminal都没问题,只是菜单栏地

址栏什么的基本看不清楚。

今天突然上网搜了一下,看到这个词antialias,突然想起来我没改过这个。赶紧看看~/.fonts.conf

。果然,里面antialias设为false,这个应该是反锯齿选项,设为true:

<edit mode=”assign” name=”antialias” >

<bool>true</bool>

</edit>

然后ctrl+alt+backspace重启x,菜单栏小字体都清晰了,Great,哈哈:-)

上几张图看看

1. 桌面的菜单 – 有锯齿,很模糊

menu turn off antialias

menu turn off antialias

2. 再看看打开反锯齿功能后的菜单

开启反锯齿效果的菜单

开启反锯齿效果的菜单

3. firefox:取消反锯齿的firefox看小字体的文字没法用,大字体还好,每次都得ctrl++来放大字体

取消反锯齿的firefox,太模糊了

取消反锯齿的firefox,太模糊了

4. 在看一下开启反锯齿效果后的firefox

开启反锯齿效果后的firefox

开启反锯齿效果后的firefox