2011辛卯年总结

家庭:

为人子

父母在,不远游,游必有方。但我做不到,为了生活,我只能苟且得生活在大城市,辛勤付出,简单的生活,节省开支,为了房子、房子、房子!!!今年帽帽出生了,母亲过来照顾他,父亲一个人留在老家,吃不好,穿不好。想到这些,更愈加惭愧内疚了。父亲60多岁,一生劳碌,先是为兄弟,后是为子女。他辛勤工作,废寝忘食,从无闲日,更无怨言,总希望子女生活得比自己好。每逢过年过节,总是不让子女回家,担心浪费路费,担心路上安全。其实心底下更多的是希望把子女守在身边,团团圆圆,享受天伦之乐。今年母亲来上海,父亲要一个人在家过年了,儿子太小,没法回家。姐姐也多次表示,车接车送,把我们接回老家,春节之后,再送回上海。但总担心刚满月的儿子不适应老家温度环境,对他身体有影响,还是打算等儿子大了,满两三个月了再回家。值得欣慰的是,姐姐跟外甥、外甥女表示,年三十晚上在自家过,大年初一就到我家,陪陪父亲。

上周周末,网上看了龙应台的《目送》前几篇,以及筷子兄弟的《父亲-父女篇》、《父亲-父女篇》(暂时没看),更是感慨颇多,对父亲思念有加。筷子兄弟的每一步作品,都能跟我们80后产生共鸣,是因为我们都有那么个童年,都有这样的父亲。没有什么比家人团聚更快乐的了。对于不打算回家的同学,请看完上述两篇短片,再做决定,三思啊。

为人夫

2011年正月初六结婚,对于我们来说,或许有点早。可对于我年迈的父母来说,已经非常晚了。我跟我老婆分别是两个省份的人,相离太远,无法完成当天“接亲”的风俗。我们的父母皆为农民,没有轿车楼房,没有达官显贵,婚礼就是那么简简单单扑扑素素的完成。由于我们当地奇怪的风俗习惯,准新娘不能在新郎的亲戚家待。而且,新娘必须12点之前迎娶到新郎家,同时,越早越好。老婆只好跟我一起,在市区的一家宾馆等待到迎娶的那天,被接到老家里。感谢老婆的信任,岳父岳母的理解,使得我这种在大城市最底层、普普通通、卑微的80后,能奢侈的完成真正意义上的裸婚。

为人父

2011年12月7号,儿子陈帽帽出生,最高兴的要属我父母了。60多岁的老头老太太,以后不用再羡慕他人,可以每天抱着孙子到处溜达,他们也可以了。可能儿子以后更多的是在我们身边,而不能经常在老家的父母身边,教育啊教育,唉…

其实,结婚生子,对我来说都太早了,但每次父母的威逼利诱、软硬兼施,搞的我每次回家过年都泪流满面的承诺尽快结婚、尽早生子。

说起儿子的名字,还挺有意思的。“帽帽”是我老婆无意中想到的,叫这个名字的小孩还挺少,基本没有。叫起来也听顺口。关于大名,在帽帽没出生之前,只是想了个女孩名,叫“陈亦初”。妈妈的解释:"亦"意为"也是"、"总是",比较委婉;"初"意为"刚刚"、"第一"等寓意。比如刘亦菲的"亦",张静初的"初"。两个字比较文雅,适合女孩名。爸爸的解释:"亦初"谐音"溢出",跟爸爸的工作有关,爸爸是个程序员。男孩的名字还没想好,直到帽帽出生了,出院前必须定好大名,情急之下,就定了“陈亦迅”,跟HK的著名歌手“陈奕迅”名字读音相同,“亦”字不一样。医院的护士跟我说,你家宝宝的名字说一遍我就记住了,哈哈。

工作:

朝气蓬勃

上半年劲头十足,目标明确,专注性能调优、架构设计。温习了正则,阅读熟悉了RFC2616、RFC3875部分章节,对xhprof、httpwatch、charles proxy等工具更加熟悉了。熟悉了浏览器的http并发数在不同http协议、不同浏览器之间的差异。最大的收获是web项目的调试技巧,尤其是后端有反响代理、负载均衡,DB、web不在同一机房,各种奇形怪状的问题。收获颇丰,这当然要感谢同事们的指点协助。尤其是netxflydeluxe1983ivon_lee等…

萎靡不振

本年度第四季度,稍有放松、士气低落、目标迷失,责任心下降,这跟我本人生活、情绪有关,感谢老大、职业欠钱等信任与包容。使得我能尽快调节自己,跳出低谷,走向正道。计划尽快转入C/C++、LUA、SOCKET相关技术的研究中去,这也是我本人研究学习的新方向。

生活:

精神食量

本年度读书13-15本,平均每月一本。包括《大话处理器》、《浪潮之巅》、《大话数据结构》、《黑客与画家》、《暗时间》、《代码之美》、《一线架构师实践指南》、《大规模Web服务开发技术》、《Rework重来》、《企鹅凶猛》、《构建高性能WEB站点》、《软件随想录》、《程序员的自我修养》、《数据结构》等。

  1. 其中《黑客与画家》我个人觉得,并没网上传说的那么好,就是一普普通通的个人从业经验感言,或许我还不到理解背后深层含义的地步。
  2. 时间管理类的《暗时间》是非常不错的,值得推荐,适合我这种注意力经常不集中的码农。
  3. 技术类《程序员的自我修养》最棒,对操作系统、编译原理、链接、装载、库、运行机制等进行原理性讲解,可惜以我目前的功力,无法全部读懂理解,目前只看了前面几章。计划先补习相关知识再看。

最期待的书就属余晟老师的《正则指引》了,之前试读过其中的“匹配原理”与“常见问题解决思路”,觉得思维方式很巧妙,我之前从来都没有理清过思路,如何去完成正则表达式的编写,分几步,每一步的目的等等。对于“匹配原理”部分,也有跟我理解不一样的地方。非常期待其他章节。

来年的计划增加数据结构、算法相关技能书的阅读,同时增加点散文类文学作品的阅读,陶冶下情操。同事说我太愤青了,换下视线吧。还有,不打算买书看了,计划到“青番茄”?借阅,除非读到非常好的书,才购买收藏。一来节省开支;而来节省空间。每次换房子,搬东西都太麻烦,书又比较重。

今年送给外甥4本书,分别是《夏洛的网》、《窗边的小豆豆》、《昆虫记》、《赛尔号》,其中《昆虫记》是一套,共6本。算是比较经济且实用的礼物了。据他们反映,最喜欢《夏洛的网》。

运动

5月初,公司举行一次户外活动,地点是崇明岛的国家森林公园,为期2天,做大巴来回。M哥、deluxe1983两位骑行爱好者决定骑车到崇明岛,中间做轮渡。我有幸也参与了,由于本人身体素质问题,体力不支,导致进展速度较慢,拖了大家后腿,各种腰酸背痛,屁股红肿….还好坚持下来了。同时,感谢netxfly的爱车。2012年最好再来一次类似的体能消耗较大的户外运动。

印迹

2011年度写博客大约6篇,平均2个月一篇,相比以为大牛60篇来说,还是非常非常的少。当然,我跟这位大牛的水平差距也非常的大,我之是他的1/100,甚至不到。2012年,由于我最近比较想读原理类的技能资料,要多多关注鸟哥春哥两位重点讲述PHP原理与Nginx原理的大牛学习。同时,要做总结自己的学习成果,并记录下来,N年之后,我退休了,这也算是经验之谈,丰富的学习资料,留给我的儿子继承了。今年,我在sina微博腾讯微博上发言的次数综合大约为1500次,平均每天5条,这足够可耻了,太浪费时间了。来年要减少微博的使用次数,增加博客的撰写。

在第三季度写了两个PPT《正则表达式匹配原理》与《WEB开发安全与运维安全浅见》,其中背后所需学习的知识点比较大,算是自我批评的一点安慰吧。2012年计划再写一个关于HTTP1.0与1.1相关的PPT,分享下我的学习经验,同时,给自己下目标,鞭策自己。

善举

2011年度从善5次,均为不超过20元的小额捐款,总计100左右。捐款对象多为山区失血儿童,还有以为是微博里传的一位白血病患者,好像也是IT从业者,性别男,为其女友发起。具体谁记不清了。明年来继续,额度不小于100元。(本人能力有限,也是社会底层的贫苦大众,富人勿嘲笑)

败家

抗得住ipad的诱惑,没扛得住ipad2的诱惑。败家4000RMB,特此反省1年,期间不能购买任何非必须的电子产品。(08年的blackberry 8800我用四年了,也算扛得住诱惑了吧。换个手机,也不为过吧?)

老友

老友牧野天涯来访一次,带了他的宝贝女儿。记得上次个他见面时,也是轻松的小夫妻。转眼间女儿就1岁多了,做了导游,逛了中国馆(世博会期间我都没去,一点兴趣都没,不知为啥),我也是第一次去,场景还凑活吧,没什么 新奇的高科技,人流仍那么凶猛。也感谢他在SEO上的相关指点。这些好友今年通话过:闫超、杲强、朱丽楠,宝发、刘威、董林、李彬、刘亚、大眼、高楠、朝阳、王勇。其他没通话过的好友,你反省,我也反省吧。

总结:

本年度评分为50分,满分100,差距较大,尤其是自我充电类计划,完成的不到40%,来年定要认真履行计划,读书15本,技术类10本,非技术类5本。由于我本人性格问题,言语中如有得罪,还请见谅。再次感谢各位同事在工作上的包容帮助。

php5.3.8中编译pdo_mysql的艰难历程

我们的一个项目,用了PDO_MYSQL拓展,准备迁移服务器,新环境需要编译安装环境。昨天,运维同事抽空编译了一下,一直编译不上pdo_mysql,同时,公司的一款新webgame临近上线,他们实在太忙,我这个三流运维技术的程序员来试试吧。

运维同事描述:
服务器系统版本:Linux version 2.6.32-71.el6.x86_64 (mockbuild@c6b6.centos.org) (gcc version 4.4.4 20100726 (Red Hat 4.4.4-13) (GCC) ) #1 SMP Fri May 20 03:51:51 BST 2011

编译PHP的参数

...
tar zxvf $soft_dir/php-5.3.8.tar.gz -C $soft_tmp
cd  $soft_tmp/php-5.3.8
 ./configure  --prefix=$soft_install/php --with-config-file-path=$soft_install/php/etc --with-mysql=$soft_install/mysql --with-mysqli=mysqlnd  --with-gd=$soft_install/gd --with-jpeg-dir=$soft_install/jpeg --with-png-dir=$soft_install/png --with-freetype-dir=$soft_install/freetype --enable-bcmath --with-mcrypt  && make && make install
...

之后再次编译 pdo_mysql 拓展

...
cd $soft_tmp/PDO_MYSQL-1.0.2/
$soft_install/php/bin/phpize
./configure --with-php-config=$soft_install/php/bin/php-config  --with-pdo-mysql=$soft_install/mysql/  && make && make install
...

之后, shell里执行 php -i 和 php -m都没有看到 pdo_mysql拓展。搜pdo_mysql,在将路径添加到php.ini中,仍找不到这个扩展,判断为编译失败。

这里是将pdo_mysql作为一个拓展引入使用的。在php5.3中,PHP开发组把mysqlnd作为默认的连接MYSQL的数据库驱动来使用,据官方描述,节省内存40%,速度更快,当然或许是为了解决许可协议的问题。之前PHP连接MYSQL,是调用MYSQL官方提供的C/C++编写的lib_mysql的dll/so,来实现。这个类库同样可以给PYTHON等脚本语言调用,只要按照API规范来。我们改用mysqlnd之后,就不用再为了lib_mysql去安装mysql client了。详情见:mysqlnd插件mysqlnd_ms的介绍
两种方法都可以,运维同事都尝试了,由于时间关系,他们没做过多的尝试研究,就转向更紧急的项目了。

运维同事下载使用的PDO_MYSQL拓展的地址是 http://pecl.php.net/package/PDO_MYSQL ,里面用很耀眼的颜色,标注如下几行字

This package is not maintained anymore and has been superseded. Package has moved to channel http://svn.php.net/viewvc/php/php-src/trunk/ext/pdo_mysql/, package ext/pdo_mysql.

也就是说,早在2006年5月1(我是根据最后一个打包文件日期猜的,或许不准)之后,PHP已经将这个pdo拓展放到PHP源码的 ext/pdo_mysql下内置了。这里的这个包,将不会在更新维护了。

在PHP官方文档上对pdo_mysql使用mysqlnd的时候,是这么描述的
在php5.3中,已经支持mysqlnd作为数据库连接驱动了。而在将来的php5.4中,将变为默认的连接驱动。如图:

mysqlnd-pdo_mysql

开启这个类库的

./configure --with-mysql=mysqlnd --with-mysqli=mysqlnd --with-pdo-mysql=mysqlnd

之后,我的编译参数如下

./configure  --prefix=/usr/local/services/php --with-config-file-path=/usr/local/services/php/etc --with-pdo-mysql=mysqlnd --with-mysql=mysqlnd --with-mysqli=mysqlnd  --with-iconv-dir=/usr/local/services/libiconv --disable-phar --with-gd=/usr/local/services/gd --with-jpeg-dir=/usr/local/services/jpeg --with-png-dir=/usr/local/services/png --with-freetype-dir=/usr/local/services/freetype --enable-bcmath --with-mcrypt

区别是使用php内置的pdo_mysql类库,使用mysqlnd作为连接驱动。

make之后,提示如下错误

soft/soft_tmp/php-5.3.8/ext/mysql/php_mysql.c:1070: undefined reference to `mysql_eof'
/data/sa/suse-soft/soft_tmp/php-5.3.8/ext/mysql/php_mysql.c:1070: undefined reference to `mysql_fetch_row'
ext/mysql/php_mysql.o: In function `zif_mysql_error':
/data/sa/suse-soft/soft_tmp/php-5.3.8/ext/mysql/php_mysql.c:1727: undefined reference to `mysql_error'
ext/mysql/php_mysql.o: In function `zif_mysql_errno':
/data/sa/suse-soft/soft_tmp/php-5.3.8/ext/mysql/php_mysql.c:1758: undefined reference to `mysql_errno'
ext/mysql/php_mysql.o: In function `php_mysql_do_connect':
/data/sa/suse-soft/soft_tmp/php-5.3.8/ext/mysql/php_mysql.c:705: undefined reference to `mysql_get_client_version'
/data/sa/suse-soft/soft_tmp/php-5.3.8/ext/mysql/php_mysql.c:963: undefined reference to `mysql_init'
/data/sa/suse-soft/soft_tmp/php-5.3.8/ext/mysql/php_mysql.c:976: undefined reference to `mysql_options'
/data/sa/suse-soft/soft_tmp/php-5.3.8/ext/mysql/php_mysql.c:980: undefined reference to `mysql_real_connect'
/data/sa/suse-soft/soft_tmp/php-5.3.8/ext/mysql/php_mysql.c:1002: undefined reference to `mysql_options'
/data/sa/suse-soft/soft_tmp/php-5.3.8/ext/mysql/php_mysql.c:706: undefined reference to `mysql_get_client_version'
/data/sa/suse-soft/soft_tmp/php-5.3.8/ext/mysql/php_mysql.c:844: undefined reference to `mysql_init'
/data/sa/suse-soft/soft_tmp/php-5.3.8/ext/mysql/php_mysql.c:850: undefined reference to `mysql_options'
/data/sa/suse-soft/soft_tmp/php-5.3.8/ext/mysql/php_mysql.c:853: undefined reference to `mysql_real_connect'
/data/sa/suse-soft/soft_tmp/php-5.3.8/ext/mysql/php_mysql.c:871: undefined reference to `mysql_options'
/data/sa/suse-soft/soft_tmp/php-5.3.8/ext/mysql/php_mysql.c:989: undefined reference to `mysql_error'
/data/sa/suse-soft/soft_tmp/php-5.3.8/ext/mysql/php_mysql.c:992: undefined reference to `mysql_errno'
/data/sa/suse-soft/soft_tmp/php-5.3.8/ext/mysql/php_mysql.c:898: undefined reference to `mysql_ping'
/data/sa/suse-soft/soft_tmp/php-5.3.8/ext/mysql/php_mysql.c:899: undefined reference to `mysql_errno'
/data/sa/suse-soft/soft_tmp/php-5.3.8/ext/mysql/php_mysql.c:901: undefined reference to `mysql_real_connect'
/data/sa/suse-soft/soft_tmp/php-5.3.8/ext/mysql/php_mysql.c:911: undefined reference to `mysql_options'
/data/sa/suse-soft/soft_tmp/php-5.3.8/ext/mysql/php_mysql.c:862: undefined reference to `mysql_error'

这种错误,让我手足无措,GOOGLE搜了下,也没找到相关案例,而且,一直被墙,打不开国外网页。百度搜的结果,还是算了。(中文还行,E文的话,百度确实不行,尤其是程序相关)
之后,尝试make clean,清除之前的编译结果缓存之类。
再次make,有个小意外

ERROR: invalid PHP executable specified by TEST_PHP_EXECUTABLE  = .....

再次搜索,这倒是很多网友遇到过,大部分的建议就是无视这个错误,不影响编译。照做。make install ,一路挺顺畅。

接着,php -i / php -m 也没发现pdo_mysql模块。
郁闷无比,决定看下web下的phpinfo结果,发现居然有了。问题终于解决了。。。万岁。。

可是!!!
1,为啥php -i 、php -m 的结果里看不到呢? 思考,为什么呢?
结合刚刚的报错,联想到CLI 模式下的php 脚本(以及相关的php.ini)跟刚刚从web下访问的php程序不是同一个。检查环境变量,以及切换到编译好的目录下执行php -i,发现pdo_mysql、mysqlnd等相关添加的模块了。

2,php.ini里没启用pdo_mysql拓展,为什么还能看的到呢?
这次使用的是PHP内置的类库,不是以新拓展方式加载运行的,所以,不用更改php.ini,再添加相关so路径。

综上所述,文章没有高深的东西,只是有几个需要细心的点。
1,以官方文档为准,一切跟着官方文档来,不轻易采信网络上网友提供的编译参数,包括这边博文。不论对方是老手、大牛,还是其他什么什么有威望的人。他们提供的方法或许跟你当前的环境不一致,时间也相差很大,或许相隔好几年了。
2,确认得到的结果是准确的,怎么说呢,文中的例子中php-i的路径不是我们新编译的,而是之前编译,或者yum安装的,一定要到自己编译的程序目录下,用自己新编译的脚本去执行测试,获得测试结果,下结论,不为了偷懒,不敲路径,直接写程序名进行测试。
3,遇到诡异的错误,我总会想要一个全新的系统,进行安装,以确保不被各种冗余、缓存等垃圾文件干扰。例子中用了make clean进行清除相关缓存,来解决文件缓存问题。(感谢@ivon_lee 的帮助)
4,自动安装脚本要及时更新,当然,不是意味着追求最新版本。例子中的pdo_mysql的拓展,官方提供了更好的方式,不论是效率,资源占用,都有更好的提升,为啥不使用呢。

备注:mysqlnd 的相关有点对比见http://developer.51cto.com/art/200903/115995.htm

PS:文中出现的我搜索无果两次错误,如果有人知道,请告诉我,谢谢。

WEB开发安全与运维安全浅见

前段时间,同事LeeQueen为公司同事做了个《安全意识防护》的PPT,效果很好,各位新同事也知道日常公工作中,不太注意到的隐私保护问题。PPT中也提到了一些社会工程学的案例,提到了某团购网站前台人员被声称是新开礼品公司的工作人员,以填写信息就送礼品为由,获取到此团购网站的所有员工联系方式。后此团购网站的高层打电话回访,得知对方是猎头公司[详情见乌云网的链接]。此案例非常典型,讨论也尤为激烈,可谓是非常成功的培训。

此次培训之后,职业欠钱[sina微博][腾讯微博]让我给我们开发部门的PHP程序员同事们做一次PHP开发、运维时候一些安全注意事项。由于我在安全这块资历较浅,没有经验,我了解的大家都懂,这个话题太高深,我的水平完全不够,没法写这个PPT。而且,同事里有好几位安全界的前辈,我怎可关公面前耍大刀呢。上次写过一次关于正则表达式PPT,也就是一个月之前,深刻的体会到写PPT的痛苦,尤其是排版。实在不想写了。

后来,经常看到网上的安全工程师提到程序员安全意识较差,以至于同样的危险代码,危险程序,却屡次不改。当然,不是程序员不想改,而是程序员不太理解代码形成安全漏洞的原因。为此,我也觉得有必要提高一下我们程序员的安全意识了。

PPT中写了网络上常见的漏洞,形成原因,漏洞原理,防护建议等;也列举了近年来跟WEB相关的安全漏洞,以程序员的视角理解漏洞原理,并给出修复建议。这些建议仅供参考,不是正确答案。 由于本人水平原因,PPT中难免有错误,请见谅。也请安全界工程师指正。

借用网友的一句话,作为程序员,尽量要做到“知其然,知其所以然”,多多关注web安全,不要给安全工程师添麻烦,不能丢了程序员的脸。

做人要有气节,不能丢了我们弄PHP的脸

同时,公司招聘PHP程序员,地点上海,公司规模为150人+,做网络游戏研发、运营。招聘条件以及待遇之类的,可以通过以下方式联系我,我们私聊。

http://weibo.com/cfc4nx
http://t.qq.com/cfc4nx
邮箱:cfc4n@博客域名点COM

最后,PPT是周末两天写的,这两天老婆挺着6个月的大肚子,为我做饭,老婆实在是太辛苦了,感谢我老婆。
PS:讨厌写PPT[流泪]。

在线阅读:

下载到本地:
PPT下载:web开发与运维安全浅见PPT下载,猛点这里
更多亮点在PPT的备注里,各位一定要看备注。转载的朋友麻烦保留PPT完整,包括招人信息。尤其是备注要保留。
——-
PPT在2011/09/19 更新了,更换匹配NGINX 对URI中PHP脚本的正则,考虑到了拓展名为 .phpa .phpb .phpc之类的情况。主要是更换了正则匹配的图,更改了正则内容。

YSLOW法则中,为什么yahoo推荐用GET代替POST?

背景:
上上周五,公司前端工程师培训,提到前端优化的一些技巧,当然不能少了yahoo yslow的优化法则。其中有这么一条“Use GET for AJAX Requests”,这些法则从最开始的14条,到现在的35条,一直都时刻关注的。可这么一条的原因我却一点都不清楚。在提问的环节里,我对yahoo WEB前端优化法则推荐AJAX中,使用GET代替POST的原因有疑问,便请教前端工程师。我们的工程师说GET的话,浏览器发送一个包,POST会发两个等等。我对这个解释仍带有疑问,甚至怀疑。培训结束后,我随便搜索了一下,并没有得到理想的结果,可能很少人对Yahoo这么有权威的组织提出的优化法则产生怀疑,也很少人想知道为什么建议这么做,更多的人会唯命是从,墨守成规。之后,我又看了遍优化法则,看到一条是推荐开发者使用AJAX缓存的,这时,一个“伟大”的想法在我脑袋中一闪,莫非是GET请求可以缓存,而POST不可以?接着,我把我这个“伟大”的猜测告诉我的同事们,当初已经是下班时间,好多同事都离开公司,我也匆忙收拾东西下班了,没有仔细查找答案。

周末期间,脑袋中频繁的闪现这个问题,仍对我的想法有怀疑,Yahoo前端这么牛X的团队的想法,岂是我这样的菜鸟能这么容易的猜测推断到的?我对我当初的推测的怀疑就像“小时候就怀疑小JJ绝对不是只用来撒尿那么简单”一样坚定。但向我这么懒惰的同学,实在找不出一点时间来验证我这个想法,空闲的时间宁愿多打几盘CS。一直拖到现在,台风来了,在家宅两天,头都睡扁了,也找不出不写这篇文章的理由。

验证Yahoo推荐的理由:
验证XHR请求中yahoo推荐用GET代替POST做法的理由

POST is implemented in the browsers as a two-step process: sending the headers first, then sending data. So it’s best to use GET
POST请求分两步:发送http headers,再发送http data

HTML+JS代码:

 <body>
<script src="jquery.1.3.2.js"></script>
<form method="post" action="">
<select name="option" id="option">
	<option value="POST" name="POST">POST</option>
	<option value="GET" name="GET">GET</option>
</select>
	<input  id="button"  type="button" value="POST提交">
</form>
<script language="JavaScript">
<!--
$('#button').click(function(){
	var option = $('#option').val();
	$.ajax({
		type: option,
		url:"cc.php",
		data: "name=cfc4n&option="+option,
		success: function(msg){
			alert(msg);
		}
	});
});
//-->
</script>
 </body>

抓包工具:wireshark
提示:wireshark(1.2.5版)在抓http包的时候,会默认合并packet reassembly选项,记得全部去掉。如下图(edit–>Preferences)

wireshark去掉 packet reassembly选项

我分别发了一个GET、一个POST的XHR(XMLHttpRequest)请求,其数据包如下:

XHR HTTP请求中GET与POST发送的数据包详情


如上图,GET请求发送的数据包为第一个红框内的结果;POST请求发送的数据包为第二个红框内结果,但多了一个第12条数据包(粉红色框内),从10.0.0.108(我的PC)发往98.126.129.106(www.cnxct.com的服务器IP,也就是表单提交的目标服务器IP),wireshark给出的信息是“Continuation or non-HTTP traffic”,这个提示就是说,本次数据包是接着上一次的HTTP请求发的,没有HTTP header,只有http data。
详情如下图
XHR HTTP POST请求的header部分数据:

XHR HTTP POST请求的header部分数据

XHR HTTP POST 请求的DATA部分:

XHR HTTP POST 请求的DATA部分

XHR HTTP POST 请求的DATA部分

结论?:
果然,如伟大的YAhoo前端团队所说,XHR HTTP的POST请求会分为两步,先发HTTP HEADER,再发HTTP DATA部分。

然而,新的疑问又来了。为什么要分为两部?谁(例如W3C这种机构)规定的?每个浏览器都是这样的么?分两次比一次的的效率更高吗?

继续:
带这我新的疑问,又进行了如下尝试:先分浏览器,IE8、Firefox5.0、Chrome13分别发送XHR GET 、XHR POST请求,抓包对比结果。

我惊奇的发现(细心的同学会注意到第三张图中,有椭圆形的框标出那些结果的浏览器是Chrome13),Firefox5发送POST的数据包确是没有像yahoo前端优化法则中提到的那样,分为两次,两个包发送,而是一次完成http headers和 http data的发送。如下图:

firefox5在发送XHR POST请求时的数据包

firefox5在发送XHR POST请求时的数据包


大家可以从图中看到line-based text data:application/x-www-from-urlcoded下面就是POST的数据。
这时,又有很多疑问产生了,其他浏览器呢?IE的所有版本都会分两次发么?Firefox的其他版本呢?
当我想一个一个尝试抓包对比的同时,幸运的搜到了关于我这个疑问的PDF(Analysis_of_browser_specific_characteristics.pdf)
其中,提到firefox大部分版本在XP、WIN7、UBUNTU、MAC OS等系统上都是以1个包来实现的,其他常见浏览器都是分为两个包。

相比大家很清楚的知道,HTTP(TCP)完成一次事务,通讯次数越多,越有可能出现故障(网络延迟等因素),开销越大,浏览器(客户端)、服务端都要再进行一次TCP通讯,而且,需要一定的时间。对于我们追求更高的用户体验,需要HTTP通讯都避免到这些缺点,而各大浏览器开发商为何仍这么做呢?firefox的做法是最好的吗?

上面的PDF里,模拟了各种网络环境,比如网络延迟、网络丢包等情况,分别来对比POST请求的1次包和2次包的优缺点。得出的结论是:当网络环境好的情况下,1次包跟2次包的在时间上差别基本可以无视。而在网络环境差的情况下,(2次包)TCP的验证数据包完整性上,有非常大的优点,客户端先告诉服务端即将发送的数据包大小,MD5等标识,当服务端告诉客户端收到(ACK包)的时候,客户端再次向服务端发送POST 的DATA。假如网络环境不好,网络延迟、丢包的时候,服务端会等待(延迟时),客户端重发POST的DATA数据到服务单,来确保本次请求的完整性。

撰写这个PDF的作者在他的博客里详细的描述了写这个博客的起因,以及结果,还有一些关于与yahoo yslow前端团队的一些沟通过程,大家可以在这里阅读下(yahoo 的前端团队好像不太友好,哈)。

结论:
通过参考这个PDF,以及我自己做的抓包测试,让我了解Yahoo YSLOW前端团队的这个推荐(他们没详细的说为啥这么推荐,只是简单的提了下GET请求产生TCP一个包;POST请求,产生2个TCP包。甚至都没告诉我们Firefox的多数版本[可能是所有版本]都是发一个TCP包的。更详细、更深层原因也没说,这里还得感谢下http://loadimpact.com的作者)。

备注:
这里提供下我抓包测试时候的数据包(截图用到的数据包中包含我的一些cookie,没上传。这里的是我新抓的,各位见谅),各位可以参考下,如果我的文字、方向有错,欢迎指出。
IE8、FF5、Chrome13发起XHR请求数据包

当你读到这里时,我承认,我骗了你,文章的内容不光是标题中所写的,为何推荐使用POST代替GET,更多的是抓去TCP、HTTP通讯包来验证各个浏览器是否如YSLOW所述的那样分2次包的过程,以及2次包与1次包的优缺点(PDF中)。希望你看到最后的时候,忘记标题讲的是什么。

《正则表达式》PPT共享(公司内部培训)

近来我越发懒惰,博客很少更新,最近在公司内部做了一个培训,关于正则表达式的,发到博客里来凑数吧,也算分享给其他朋友了。至于正则表达式的重要性,想必不用我说了吧。

发明BSD、TCP/IP、csh、vi和NFS的SUN首席科学家Bill Joy说过,在计算机体系结构领域里,缓存是唯一称得上伟大的思想的。其他的一切发明和技术不过是在不同场景下应用这一思想而已。在计算机软件领域里,情形也大体相似。如果罗列这个领域的伟大发明,绝对不超过二十项。这些包括分组交换网络、WEB、lisp、哈希算法、UNIX、编译技术、关系模型、面向对象、XML这些大名鼎鼎的家伙,而正则表达式绝对不应该被漏掉。

你还记得大学时候的课程编译原理中提到的 NFA\DFA 吗?还有印象吗?你知道PHP编译器扫描你写的PHP代码字符串的时候,是如何区分哪个是变量,哪个是常量的吗?你知道SQL语法分析器是如何判断你的WHERE条件中出现的SELECT\FROM\ WHERE等关键字是字符串,而不是子查询等关键字的?
你知道.ini配置文件跟xml配置文件对程序来说,是如何扫描解析的吗?他们一样吗?如果你想知道,那你务必的熟悉正则表达式,精通正则表达式。不光能写出正则实现功能,还得能写出高效的正则表达式。(编译原理的课程里,有关于NFA\DNA的大篇幅描述,想写出自己的编程语言,正则是躲不掉的。)

不扯淡了,附PPT吧。
(PPT模版是网上网友的,我是借用他的,其中有几张PPT是直接用他的。很好区分,动画效果很炫的(主要是文字层下的颜色,大约10页吧,简单描述那几页)就是原作者的,其他都是我自己写的。作者信息在PPT最后一页有)
PDF也放出来,效果没PPTX好,很多层都被遮住了。

猛击这里下载《正则表达式》PPTX

或者您也可以在线阅读:

编译xhprof时的一个小意外

新项目基本开发完毕,剩余收尾工作。趁美工调整新UI的时间,赶紧在测试机上安装PHP的性能检测利器xhprof。
下载地址http://pecl.php.net/package/xhprof,这里有tar包,我下了http://pecl.php.net/get/xhprof-0.9.2.tgz

tar zxvf xhprof-0.9.2.tgz
cd xhprof-0.9.2
cp -r xhprof_html xhprof_lib <directory_for_htdocs> # 应用程序所在目录,其中xhprof_lib是生成统计数据用到的类库。xhprof_html是查看统计数据的时候,用到的类库。
cd extension
/usr/local/php/bin/phpize
./configure
make
make install

之后,遍完成了。一路很“顺利”。
php.ini如下设置

extension=xhprof.so
; 存放目录,这个目录用来存放统计程序性能生成的数据。要有读写权限。
xhprof.output_dir=/var/xhprof_data

代码中,程序头部如下设置:

xhprof_enable(XHPROF_FLAGS_CPU + XHPROF_FLAGS_MEMORY);

程序最下面:

$xhprof_data = xhprof_disable();
include_once "./xhprof_lib/utils/xhprof_lib.php";
include_once "./xhprof_lib/utils/xhprof_runs.php";
$xhprof_runs = new XHProfRuns_Default();
$run_id = $xhprof_runs->save_run($xhprof_data, 'xhprof');
echo 'http://<xhprof-ui-address >/index.php?run='.$run_id.'&source=xhprof';//source的值就是save_run的第二个参数的值。其中,网址就是上面保存xhprof_html的路径。

之后遍看到统计数据结果了。

可是,当我查看[View Full Callgraph]的时候,却提示如下:Error: either we can not find profile data for run_id 4d7f0bd99a12f or the threshold 0.01 is too small or you do not have ‘dot’ image generation utility installed.,这TMD神马玩意?是什么错呢?
关于dot的介绍,xhprof在这里写出来了:
http://mirror.facebook.net/facebook/xhprof/doc.html

dot (image generation utility): The callgraph image visualization ([View Callgraph]) feature relies on the presence of Graphviz “dot” utility in your path. “dot” is a utility to draw/generate an image for a directed graph.

GOOGLE了半天,也没找到可用的信息。问了下群里的同学,大牛老王告诉俺,xhprof绘制的是png图,系统(graphviz-2.24.0)不支持。才知道绘图的dot拓展没装成功。我的操作系统是UBUNTU 10.10 SERVER版的,也就是dot 不支持PNG。赶紧再次编译下graphviz,看看提示信息有什么缺少的。果然:

options:
  cgraph:        No (disabled by default - experimental)
  codegens:      No (disabled by default - deprecated)
  digcola:       Yes
  expat:         No (missing library)
  fontconfig:    No (missing fontconfig-config)
  freetype:      No (missing freetype-config)
  glut:          No (missing GL/glut.h)
  gts:           No (gts library not available)
  ipsepcola:     No (disabled by default - C++ portability issues)
  ltdl:          Yes
  ortho:         No (disabled by default - experimental)
  png:           No (missing png.h)

png: No (missing png.h)果然。。。。
赶紧到libpng官网down分源码,再次编译一下。
SF.NET上地址是 http://sourceforge.net/projects/libpng/files/libpng15/1.5.1/,我下的是http://sourceforge.net/projects/libpng/files/libpng15/1.5.1/libpng-1.5.1.tar.gz/download ,一气呵成,很顺利。
再次编译graphviz的时候,提示如下:

 ortho:         No (disabled by default - experimental)
  png:           Yes

好了,内牛满面。之后就是 make&make install了。
当打开[View Full Callgraph]的时候,果然是性感的资源占用统计图了。
展示下效果图:
优化前:

xhprof性能监控图优化前

xhprof性能监控图优化前

找到问题所在,稍微调试:

xhprof性能监控图找到问题,调试中

xhprof性能监控图找到问题,调试中

最终代码优化结果:

xhprof性能监控图优化结果

xhprof性能监控图优化结果

程序员的谦逊编程

译注:开发人员如何从无休止的需求、项目进度中摆脱烦躁的心态,这是每个人都值得思考的话题。无意间看见了这篇文章,恐于太长遂将其精简翻译,错误之处难免欢迎指正。

同时如果你有有关程序员修身养性的观点和心得,欢迎说说你的看法。

-- Split --

其实每个程序员或多或少都会有个毛病,就是具有某种有强烈的“优越感”。而这种“优越感” 有可能成为激励自身不断发展的动力,同时也有可能成为其职场中的绊脚石。

程序员的这种心态,源自自身掌握的技术、以及多年积累的经验。正如上面所言,这种心态 能使其一切都力求完美、同时准确按照自己的思路行事,能使其技术不断的提升。而另一方 面,如果将这种态度套用给身边其他的人(包括陌生人、同事、朋友甚至家庭),则会发现 他的生活将会如履薄冰 — 他们只会看见完美的一面而忽略了更多更需要关注的事物。

总而言之,越早发现并解决这一问题,越对自身有利。套用 GeraldWeinberg 在《计算机编程心理学》中的一段话

这种想法是程序员必须解决的,他们对待自己的代码犹如对待自己身体的
一部分,因此他们拒绝所有的负面评价。相反,它们(指代这种心态)应
该及时的引导到正途,使其发挥真正的效用。人非圣贤,这不仅仅是心态
更是精神上的境界,并非所有人都能达到,但仍旧值得去尝试。

症状

那么,你如何得知这种“优越感”正在伤害到自己?除了应付那些没完没了的催促项目进度的 电话,以及给同事擦屁股的优化工程,其它的现象并非显而易见。

其实就我个人而言,时常也会自我责备,这就能窥出事态的严重。例如一方面你对项目疲于 奔命,而同时却忽略身边的人对你表达的看法(该死,这个时候我应该放下手头的工作听他 们说完的)。或者你“假装”静下心来听取他们的意见,但不就繁杂的工作却让你左耳进右耳 出。

其他的些症状

  • 如上面所说的,不会妥善处理批评
  • 不放心同伴的代码,经常性地对他们进行代码审查(Review)
  • 报复性的编写大量充斥着错误的代码
  • 个人的消极心态,对自身和团队造成不利的影响
  • 必须要求进行测试,但出发点却是炫耀
  • 对事物的看法仅仅局限于个人或者本职位的角度

这不仅仅是你个人的事情,编程以及项目开发实际上是团队活动。了解到这些,你将会意识到 你的心态将会直接影响到你的同事。

事实就是这样,当我对您的代码提出写意见甚至批评时,你应该听、并且认
真的听,这样你才能理解我的看法。

有可能最糟糕的情况就是,即便早已经收到其他同事的提醒,当事人已经陷入此泥潭无法自拔。

准则

让我们回到文章的题目本身,正如上面的例子中看到,“谦逊编程”不是编程技术本身,而是 种态度,但它的确会比你掌握的某种技术要有用的得多。

行为准则的确能改变人的心态,下面是些不成文的建议,或许你可以尝试下

  • 不要草率的宣布你的决定,在大多数情况下,你应该和你们的同事们讨论
  • 不要使用这些论调,这非常让人感到不适:“这是见过的最糟糕的代码了”,换之你可以这样说,“我有个更好的解决方案,要不看看?”
  • 不要轻易认为他们没有考虑到你想的方式,即便很不幸是这样,应该善意的提醒。例如“你觉得我这个看法怎么样…”
  • 不要无理由的批评你认为很弱智的现象,例如“我觉得 DBA 脑门子被夹了,这个字段竟然使用 INT 型”

更多的,可以参考 Tech Republic 中的“谦逊编程”十条诫律

  • 理解和接受你将犯下的“错误”。
    重点是及早的发现你已经犯下的错误,当代码投入使用以后,改动起来就会非常的困难。
  • 你的代码不能代表你的人。
    记住始终要 Review 你的代码,即便你已经认为无懈可击,经验证明总能发现些错误。
  • 不管怎么样,有些“奇技淫巧”总能派上用场,而可能这些技巧别人知道的比你更多。
    如果你坚持不耻下问,你的同伴总能分享你更多。
  • 不要在完全没有沟通的情况下,自作多情的进行代码重构。
    当你确定要更改别人的代码时,必须加上良好的修改记录,这也是出于对他人的种尊重。
  • 对待那些新手要保持充分的尊重、细心以及耐心。
    记住当他们成长起来后,能帮你解决的问题会比你想象中的还要多。
  • 唯一不变的是变化。
    怀着开放的心态对待变化,对于各种需求、平台甚至开发工具的变更,应该是迅速适应而不是牢骚满腹 — 这样解决不了问题。
  • 真正的权威来自学识,而不是立场。
    权威源自学识、尊重源自权威。
  • 优雅的接受失败。
    最终你的一些观点将会被推翻,即便你有能力证明你的观点是正确的,请不要重复的争辩。帮助其他人意识到这点的最好工具,就是你的理解以及时间。
  • 不要成为“办公室男”。
    不要在昏暗的办公室里独自喝着可乐敲着代码。当与外界隔绝,离开同伴的视线,也就说明你离开了一个开放、合作的环境。
  • 批判代码而不是编写它的人。
    要知道你的意见可以影响到代码也可以影响到其人,如果你想尝试下如何打击别人的自信并造成冲突,那么尝试下吧。

此文转载自:http://www.gracecode.com/archives/2971/ ,自勉自勉。

为什么使用ubuntu server的会被鄙视?

由于个人经历原因,我在06年经Dancefire推荐,才认识ubuntu的。时至今日,已有5、6年了。对着ubuntu有着莫名的喜爱。ubuntu桌面版的易用性,友好性,使得我这个菜鸟很容易的入门了。
如今,在公司的svn服务器系统选择上,我也选了ubuntu。
近期,重写了passport系统,出于好奇心,好奇自己的登录程序的并发处理能力、占用资源情况等,想压力测试一下,并不是项目真正完成的时候进行的测试。测试环境一切都是ubuntu的apt之后默认安装的配置。测试中发现瓶颈在DB,顺便让DBA帮看下哪里需要优化的。不想却被一位同事鄙视(善意的鄙视)一番,嘲笑我选择了ubuntu server。我很纳闷,我对linux不熟悉,找不到强有力的理由来反驳。不过,我觉得,不选择ubuntu的理由不能是向他所说的“哪有公司用ubuntu server?”。容我直白的说,如果真的这么想的话,我觉得这可能有些“井底之蛙”了。可能是ubuntu pc版本的界面,比较漂亮,安装软件更傻瓜化,点点鼠标的事情。软件的源很多,基本不用编译等等这些原因,认为使用ubuntu的人都是菜鸟级的。认为全是命令行的界面,所有软件都亲自编译那才叫高手。。。如果要是从内核上找优点,论证这些强项,我会更容易接受你的看法。
比起快速部署,我想,ubuntu server应该比centos之类redhat系的要快的多吧。至于觉得安装的没有编译的效率高,这些可以通过配置文件来设置吧。ubuntu更新比较频繁,可能在升级生,不会很平滑。
对于比较那种linux的server比较好的这种比较,就跟比较 asp.net、PHP、jSP、python等脚本语言比较牛B一样没有意义。更多的在于使用者,而不在于语言本身。如何选择,就看哪种自己更熟悉,更习惯。当然,我也是瞎扯了。我对linux基本不熟悉的。

顺便附上2011年-01-19的linux市场份额图:

2011年-01-19的linux市场份额图

其中,centos占了29%,ubuntu占了12.3%,也算不少了吧。

原文地址:http://w3techs.com/technologies/details/os-linux/all/all

正则表达式与数学(方程式、线性方程)

大清早的打QQ去,收到一位网友的信息。问得是正则表达式判断素数的。去年看到过,没记录下来。
正则表达式如下:

^1?$|^(11+?)\1+$ 可以判断素数(换成n个1的形式,n为数字的大小。比如5转换为11111;3转换为111;2转换为11。)

什么是素数?
初中学的吧。我们老师当初教我们的是“质数”。看下概念:
质数又称素数。指在一个大于1的自然数中,除了1和此整数自身外,没法被其他自然数整除的数。
换句话说,只有两个正因数(1和自己)的自然数即为素数。比1大但不是素数的数称为合数。1和0既非素数也非合数。

这个正则表达式是什么意思?
【^1?$|^(11+?)\1+$】中间用【|】分开。【|】在正则语法里,表示“或”,作用于其前后两个单元。(还是不明白的看下面,明白的跳过下面这段)

比如【ab|cd】可以匹配“ab”、也可以匹配“cd”,意思是除了“ab”就是“bc”,如果想匹配“abd”、“acd”那【|】的作用域得改下,加个范围
改成【a(b|c)】(匹配结果分配组)或者【a(?:b|c)d】(匹配结果不分配组,更高效率)。

继续刚刚的正则,分为两个分支,其一为【^1?$】和【^(11+?)\1+$】。其中【^】脱字符在正则语法中,除了在中括号【[]】中都是代表开头的意思,在中括号中的表示非。
第一个分支【^1?$】匹配的是“1”或者“”(空字符串)。
第二个分支【^(11+?)\1+$】,先看下括号内的【(11+?)】匹配的是字符“1”后面接着【1+】就是1到无数个1。后面的【?】问号表示非贪婪,就是尽量少的匹配。
接着往后看【\1+】中,【\1】表示引用已匹配的第一个组的结果。也就是第一个【()】括号匹配的结果。同理【\2】就是第二个括号捕获的结果。(小提示:上面提到的【(?:)写法就是不分配组,这样引用的话,就引用不到了】)
【+】就是1到无数个了。这个表达式我们可以这么看。【(11+?)】看成数学中的1+n,其中n为大于0的正整数。外面的【\1+】也就是引用前面这个组的次数。理解成m倍,其中m为大于0的正整数。
那整个表达式就是(1+n)*m。因为n、m都大于0,那么1+n肯定大于1,最小为2,最大为无穷大;m最小为1,最大为无穷大。
那么,一个大于2的正整数的任何大于零的倍数永远都是合数,也就是非素数。

再回过头来看看这个表达式。匹配的分别为0个或1个字符串“1”,也就是数字0,数字1。和其他所有合数。整个表达式,如果成功匹配就是非素数,如果不匹配就是质数。这就是对的了。

if (preg_match('/^1?$|^(11+?)\1+$/i', $subject)) {
	#不是素数
} else {
	# 是素数
}

小提示:此鉴定是否为素数方法仅研究学习用,不能用到正式程序中,字符串过长,会造成非常恐惧大的回溯

英文博客地址:http://blog.stevenlevithan.com/archives/algebra-with-regexes

在上面的博文中,有提到两个方程式与正则表达式,我们一起来研究下。

  • 二元方程17x + 12y = 51,其表达式【^(.*)\1{16}(.*)\2{11}$】。很好理解。【(.*)】也就是0到无数个【.】点号。(这里是接着上文说的,其实,【.】点号想表示的是字符“1”)
    也就是0到无数个1,后面【\1】引用一次。后面【{16}】就是16次。作用于前面的【\1】,也就是16次引用。加上开始的【(.*)】一共正好17次。后面一个就不说了,跟这个一样。
    正则引擎会依次尝试【(.*)】中0到无数个字符“1”,0个字符“1”,1个字符“1”,2个字符“1”一直增加的尝试。直到成功,否则要尝试完所有字符“1”的最大个数(这里是51个字符“1”)。
  • 二、三元方程式11x + 2y + 5z = 115,其表达式为【^(.*)\1{10}(.*)\2{1}(.*)\3{4}$】,理解就跟上面那个一样。注意【\2】、【\3】值得是第2,第3个括号捕获的内容,别看花眼了。

——————-分割线——————
上面几个有意思的数学题都是将整数转换为对应个数的字符“1”。下面这个,是转换为二进制数的。
先吃饭,以后再写。

朝三暮四,还是朝四暮三?

朝三暮四是个老典故:古时候宋国有个人养了一群猴子,早上喂它们三颗果子,晚上四颗,猴子就恼怒;如果改成早上四颗,晚上三颗,猴子就高兴了。小时候听了这个故事,总觉得猴子太傻:反正每天都是七颗果子,何必在乎早晚呢?长大了做许多事情也是如此,反正总量不变,朝三暮四还是朝四暮三,只有时间的差别而已,想找出什么分别都是徒劳,还不如索性从容点。而且,许多人的潜意识里似乎也这样认为的,至少争辩起来,许多人都会这样反驳,典型的句式就是“反正……,何必呢?” 可是,我又逐渐发现,有些事情似乎不是这样的。

就从生活的小事说起吧:现在物价飞涨,当过家的人都知道,有些菜简直是一天一个价,许多事情就不再是“早晚一样”了,能赶早的就得尽量赶早,否则,拿同样的钱,就买不到同样多的菜,要买同样多的菜,花的钱就不一样。换句话说,在迅速变化的形势面前,朝三暮四还是朝四暮三,就不再只有时间的差别,而是有了实实在在的不同。

而且,即便不是在迅速变化的形势下,朝三暮四和朝四暮三,也可能存在真正的分别。还是拿我自己当例子,我生活还算规律,晚上一般十二点左右睡觉,早上六点半起床,之后要锻炼、读读书、收拾收拾,八点多出门上班,时间充裕,动作从容,自己也比较满意。可是有一天,周老师跟我说,晚上早点睡觉,早上早点起床,这样可以做的事情多得多。开始我并不相信,抱着怀疑的态度尝试了几天之后,发现果然如此。可是,这是为什么呢?我仔细思考之后,终于找到了原因:我自己习惯每天要认真读点书学习点资料,大概是每天2小时左右,以前因为早上六点半起床,留给看书的时间大概是二十到三十分钟,刚刚进入状态,想清楚几个题,就得去忙别的了。提早到五点半起床之后,留出来看书思考的时间就多了很多,夸张点说,可以很从容地安排两节自习课。相应的,晚上不必看那么长时间的书,也更容易保持清醒的头脑,效率也高了不少。看来,“朝三暮四还是朝四暮三”的道理,也可以用在学习上:相比之下,“每天学习xx小时”这样的目标,还是显得太粗了,更细致更妥善的安排,完全可以收获更好的效果。

前些年我读冯仑先生写的《野蛮生长》,也见到了道理:年轻的时候,到底是多玩乐一些好,还是多积累一些好?对这个问题,他似乎并没有给出明确的答案,如果一生中用来积累的总量和玩乐的总量差不多,年轻的时候多积累一些,虽然看起来玩的少了点,但年纪大的时候收益更多一些,玩起来的后顾之忧也少一些;如果年轻的时候玩得多一些,老了就得花更多的精力补上积累的课。我想这说法确实有道理,此类问题也确实不宜从“总量一定”的角度来看:积累和玩乐之间,到底是选择朝三暮四,还是朝四暮三,它们之间,远远不只是时间的差别。

本文由Yurii《精通正则表达式》译者余晟老湿原创。引自:http://www.luanxiang.org/blog/archives/1089.html

第 1 页,共 13 页12345...10...最旧 »

CNXCT小组的博客 is Stephen Fry proof thanks to caching by WP Super Cache