Shell's Home

Nov 23, 2011 - 1 minute read - Comments

新手?新手!

《新手?为什么需要关怀》在42区上挺热,看到很多人留言说新手,诚惶诚恐。我说你们也别太那啥了,一般只要不是求作业求妹子的,基本都还是能忍的。就算你问问题前言不搭后语,问题叙述的乱七八糟,老是求解释。通常我最多告诉你看某文档就不再回话——意思是事情到此为止。你不用担心我恼怒或者生气,我的时间很宝贵,没空浪费在这么无聊的事情上。如果下次你问出个有内涵的问题,咱们不妨讨论讨论。 写这篇的主要目地,是给新手一个指导。我不知道现在所谓新手的水准,以我在42区上看到的而言,是高的吓人。但是我实际接触到的,可能如一位朋友所说的垃圾,水准是差的吓人。其中有很多是不高兴学,或者打算做了再说的。您走好,这篇文章不是给您的。这篇文章是告诉一些真的是新手的程序员,如何稍微的提高一点水平。我假定你们会用vc写一些简单的程序,拖拖拉拉控件能做一个简单的计算器。在计算机上,我相对偏向实用。您和我说在算法课上能拿多少分,对我今天所说的内容意义不大。所以无论您课业上不及格也好,满分也好,本文告诉你如何成为一位牛逼或者可以装逼的程序员——如果你做了整个过程,学到了东西,那就是前者。如果没学到,没关系,至少你可以拿着本文的经历去装逼。 首先,请保存好你们的照片什么的,然后,把你们面前的电脑格式化掉。对,所有windows的内容一点不要留,已经是linux的朋友,请确保你“没有”windows了。作为程序员,你无论如何都需要自己做很多事情,直接使用linux是一个良好的开端。但是学linux是痛苦的,只要有退回windows的可能,你就没法真的学会linux。学着用linux工作和学习(对于某些人来说,娱乐更重要,在这方面,linux确实不怎么样,幸好,如果您是这样的人,本文也没看的必要了),并且熟悉整个系统,最快需要2-3个月的时间,慢的话需要半年到一年的努力。你需要不断磨合,学习新的程序使用方法,请教前辈,实验,最终能够掌握这一系统。掌握的标准是什么?你知道哪些事情是不能用linux做的。之所以这么说,是因为新手根本不知道哪些事情是不能用linux做的,他们所有事情都没法用linux做。而老手会使用最合适的方法来用这个系统。 当你已经能够熟练使用linux,甚至比windows还熟的时候,你的桌面装什么东西就随便你了。我的桌面是win7,因为老婆需要。我知道不少程序员的桌面是mac,这也很好。不过一旦你熟悉了linux,你最少会装个虚拟机来做开发,并且觉得试图在windows下做这些事情很蠢。windows的console是cp936编码的,网页很多都是gb2312编码的,但是用gb2312去读他们却未必能行(这是因为windows下的gb2312/gbk说的都是gbk,抽风啊)。linux下面大多数term都是utf-8,世界清静很多。windows下开个小网页服务器要跟着一个图形管理界面,linux下服务就是服务。总之,如果你真的打算开发,你会发现windows其实非常不友好。所谓友好是指已经被微软封装过的部分,还有他们的文档——那个真的非常不错。 第二步,你得打造一个自己的工作环境。我知道你习惯了微软的IDE,进入linux后还试图用一些WYSIWYG的系统。不是每个WYSIWYG都是错误的,然而作为最适合你的程序而言,他未必就是WYSIWYG的。你在windows下一般用什么开发工具?vs?盗版吧?好吧,你是学生。但是你能用vs编译一个linux kernel么?在没有SDK扩展包的情况下,vs也不能用来做android开发吧?这就是vs的真相,将一些特定的开发,做相当程度的简化,以换取大量的初级开发者。当然,你会反驳说vs可以开发WDM,或者做DDK级调试都可以。然而,这也是特定领域——凡是微软给你能做的领域,你都可以做。但是微软不允许你做的领域呢?虽然微软允许的范围很大,但是作为初学者,了解开发是如何工作的更加重要。 你可能需要一个编辑器,通常这只有三个选项,vim/emacs/其他。而后你需要一个编译器,如果使用C,多半就是gcc。调试工具一般会选用gdb,编译项目管理工具一般是make。这四者的用法都可以google到,并且通过合适的配置配合到一起,达到和vs类似的结果——你写一些代码,然后按开始调试,程序就开始一步一步运行。到你需要的地方,输出一些数据看看?然后再继续运行。和vs没有什么太大差异。不过作为自行配置环境努力的回报,你有两项比较大的优势。一个是你的各种工具都是千锤百炼的,最优化的工具,他们一定真的能工作,而且可以信赖。另一方面,当你需要改变工具的时候,你可以保持其他工具不变。例如,你现在需要通过go语言快速的开发一些web程序,你需要将gcc换成gogcc,gdb也需要换掉。然而make只需要新增一些规则,vim/emacs也无需变化。回想一下你在vs里面如何编写go代码?——这个——好像——似乎——需要第三方插件吧。找找看?运气好的话有收费插件可以达到这个目地,找一个破解版来——如果开发者都对破解无动于衷,你还如何指望别人来尊重你的知识产权?也许你想,我可以不使用go语言来编写。好吧,go的效率是编译型语言中比较高的,你要和go比效率,可选的只有C语言。那么你准备在vs上用C开发一套web?——我尊重你的选择,并为你逝去的人生默哀。 第三步,找一个合适的项目。这点我在《如何参与一个开源项目》一文中有说,不过那篇文章建议你尽量做一些代码之外的工作。为了磨练你的水平,你可能需要做一些和代码有关的事情。不过无所谓,大概来说事情是不变的。找一个合适的项目,和他的领导者谈谈,看看有什么可以干的,并且努力干完。 第四步?没有了,继续这么干吧,应该没多久,你就是N个项目的参与者,有一定的代码贡献,并且和一些大牛们交流一些业界最新的东西。如果这样都不算入门,我真不知道你入门的标准是什么了。 听起来很简单,那么事情的难点在哪里? 关键在于,无论事情看起来多么困难,多么不可能,你觉得多么辛苦,你都立刻,马上的去做。而不是看完文章后点一下“mark”,“like”,“+1”,然后让他躺在你庞大的文库里面生灰。

Nov 22, 2011 - 1 minute read - Comments

python-segment使用示例

项目的主页是http://code.google.com/p/python-segment/,如果有问题,可以在上面提交issue,我会收到邮件(google code会么?应该会吧)。如果你希望协助开发,可以加入项目。一些简单问题可以直接看项目的WIKI,Wiki中有的一些内容我不会进一步解释,只会告诉你在那里可以看到。 1.如何获得源码 你可以使用以下代码,直接从版本库中复制一个可用版本出来。 hg clone https://shell909090@code.google.com/p/python-segment/ 或者可以从这里下载一个最新版本的包。 2.如何准备环境 你可以看INSTALL,里面讲解的比较详细了。如果你不准备进行安装部署,可以跳过安装和打包这两步。但是如果你打算使用cutter工具,请安装chardet。如果你打算使用spider工具,请安装html2text。 首先按照如下方式生成词典。 gunzip dict.tar.gz ./ps_dbmgr create dict.txt 然后,你可以看到生成了frq.db,这是词典的默认文件名。注意,词典文件的格式和具体的版本有关,换用版本后最好重新生成词典。 3.试验分词 假定有一个文本文件,test.txt,里面内容是中文平文本,编码任意。 ./ps_cutter cutshow test.txt cutter会自动推测编码。 4.代码使用 假如当前有一个frq.db词库。 import segment cut = segment.get_cutter('frq.db') print list(cut.parse(u'工信处女干事每月经过下属科室都要亲口交代24口交换机等技术性器件的安装工作')) 注意,仅仅使用parse是不会进行分词的,因为parse返回的是一个生成器。

Nov 21, 2011 - 1 minute read - Comments

新手?为什么需要关怀?

最近老是收到“新手,求帮助”的邮件,很多人很有礼貌,但是实话说,我总觉得这些新手邮件的想法有问题。今天不妨开诚布公的说一下我对新手的态度。 很多人总是很客气的发邮件“新手,求帮助”,里面提出一些很傻的问题——这不奇怪,无论多强的人都有傻傻的时候。这些邮件写的也很客气,一切没有什么不对。除了一点——其中某些邮件中总是充斥着一股说不出的“不劳而获”或者“傲娇”的情绪。说的更直白点,就是“我们是新手,所以说的简单点,但是又要说明白”,”XXX的最好途径是什么?适用于新手哦“,或者更过分的“我的作业马上要截稿了”,“我女朋友要我做题”。 实话说,我对一个人是不是新手并没有太多兴趣。新手对我的区别只有——你没有关于XXX的相关背景知识,所以,也许你要先看OOO书,有一个大致概念,然后再看XXX文档,详细了解一下,然后你看XX书,就能够解答你的疑惑了。这是知识依赖的关系,你没有相关知识,自然看不明白。作为声明新手的结论,我会帮你指出你所需要的知识在哪里能够找到,免除你自己去google,还有可能找不到的困扰。差不多这就是我能为新手做的所有事情了。 至于那些说,为什么不把相关知识截取下来发出来,为什么不详细解答疑惑的人,我没什么好多说的。如果新手的行为就一定是可原谅的,我们每个人都会在路上横冲直撞。我们总会在某个领域成为新手——哪怕有10年经验的程序员,也会是一个新手驾驶员,或者新手厨师。作为新手驾驶员,我们有责任通知别人——躲我们远点。并不是因为我们是可原谅的,而是因为我们不能自制的作出不可原谅的事情。作为厨师,尤其是程序员厨师,这点更加明显。程序界有句行话叫做——吃自己的狗粮(eat your dog food),意思是自己做的程序一定要自己用一下才有体会。同样,厨师自己做的菜一定要自己先吃,自己都不敢吃的东西是不好意思端出来的——哪怕我们都知道你是新手。 没人应当对你的无知负责,你自己无需负责,你父母无需负责,我也无需负责。人总是新手,但这不代表老手要无偿的呕心沥血教会你——哪怕他是个教师。新手没什么了不起,或者值得无限原谅的地方。你到底是我的老板呢?还是我的衣食父母呢?我需要为你把所有的材料看一遍,摘出合适的部分,讲给你听,并且还保证你能够学会。我想即使是老师,也不会帮你做这些事情的。不要和我说论文马上就要截稿,或者你们老板多黑心,你女朋友和人跑了,或者你这课挂了,就白花了四年的时间和无数的钱——这些钱和时间都是你自己浪费出去的,我帮你解决问题并不能节约下来这些时间和钱,这样只会浪费我的时间。何况如果我用最快的方法教会你,你出来后不是就直接和我竞争了。你看,我不但包教包会,而且成功后还要降低自己的工资——我要多么的脑子进水,才会干这种损己损到家的傻事呢? 而且,作为一个要辛辛苦苦从学校招一些靠谱的学生的程序员。我无比的痛恨出题太简单的老师——虽然我在学生的时候痛恨的是出题太难的。题目可以抄,出题太简单,找人代写,改头换面,和老师搞好关系。这一切我们在学生时期耍的小聪明,到了工作中都会结结实实的还给我们自己,除非你不从事技术相关行业。如果你从事的是销售行业,这些小聪明,手腕和技巧,也许是有帮助的。但是作为技术行业,这一切是我们深恶痛绝的根源。新毕业出来的学生中,大概只有不到一成的人理解为什么java不能使用双重检查成例——哪怕你详细的给他们讲解原理,他们仍旧一头雾水。因为从一开始,最基础的,理解关于锁定和单例的相关技巧,就没被认真的学起来过。大多数的人都可以熟练的作出B+树的实现,或者排序算法——因为这是考试时需要的东西。但是你在和他们谈论实践技巧的时候,会非常伤心的发现,他们所谓的实践技巧,就是在某个特定的框架上,如何用教科书上的方法搭建出一个网站,或者是应用程序。如此我大概就知道,为什么我们全国一年有将近200W的计算机系毕业生,但是全国程序员总数才150W上下——这是07年的数据吧。 其中有一些比较靠谱的人,是真心想学好计算机的——我姑且不论理由是爱好,还是因为程序员工资比较高。但是这些人的信件里面,也有说不清的傲娇情绪。我为什么要对你负责,把具体过程实现给你?因为你说的比较好听?抱歉,就算是MM,我也已经结婚了,所以对你没兴趣。如我上文所说,我最多告诉你,从理论上这样可行。至于我是不是有能力实现,或者为什么不实现给你,这个和你没有关系。如果你自己不高兴去翻那厚厚的一叠文档,那就保持不会好了,我在招人的时候会轻松很多,而且你也会少很多伤心往事。我知道不少公司招人的时候,往往会出一道题。然后有那么几个学生,题目解答的异常完美。这个故事的结局往往两级分化,一种是这个公司把所有的优秀解答凑一凑,直接取消了这个职位。另一是这几个学生进公司后,一塌糊涂一头雾水,结果连试用期的三分之一时间都没过去就被一脚踢出大门——仔细看看你们的合同,试用期辞退是不是不用赔偿? 工作不是考试,只要技巧过关,一次通过,没人能找你麻烦。工作,尤其是技术工作,是一个长达数周乃至数年的过程。没有足够功底的人会在几天内被戳穿,然后扔出去。我知道你们会怎么做,你们会在简历中添加这家公司,然后向下家编造一个公司不靠谱的理由——阶级斗争啦,项目做完啦,或者如我上文所说的,凑凑答案取消职位啦——看看他们会不会买你的帐。如果他们做了背景调查,你没有机会。如果他们没做,你的简历上就会又添加一笔资历。三五次后,你就成为在多个公司供职的高手,月薪一次比一次写的高。大多数的HR不是傻瓜,如果真有这种高手,他们绝对不会投出简历然后乖乖的前来面试。通常这种人的手机上有N个猎头的未接来电,想要跳槽的消息传出去后,简历还没开始动笔已经有人开出了天价的薪水。如果有那么个冤大头愿意相信你,我得说,你的传销技巧做的很好。不过大部分这样做的学生,最后都去了销售职位。至于他们的结局,我就没有关心过了。 所以,干脆让我们省掉这些无聊的功夫吧。您不如直接去销售职位,我就去安安心心的挑一些不是那么无药可救的学生。看看他们能不能安下心来看这些文档,在一个个不能成眠的夜晚悔不当初,为什么不在别人指出这些资料后就去老老实实的看一遍。那些看了的学生?他们在被猎头围追堵截中,我就不凑热闹了。

Nov 18, 2011 - 1 minute read - Comments

openwrt特性——2.4g和5g频段的冲突

贝壳昨天想起,自己的平板是支持11n的,路由器也支持,为啥不做呢?于是把路由器的第二AP打开。结果——报错了。 具体过程就不废话了,老妈和外婆在唠叨各种废话,没那个心情。 DIR-825用户,把你的第二AP设定成和第一AP不同的频率。如果两者使用同一频率段,系统就会报错。估计是两个频率各自给了一根天线,混用没那么多天线。

Nov 16, 2011 - 1 minute read - Comments

mongo无法利用多核?

太伤心了,本来以为mongo的速度很快呢。测试插入数据,结果当场被泼了冷水。 conn = pymongo.Connection('localhost', 27017) db = conn['perform'] coll = db['test'] testdata = [] def init_testdata(): for i in xrange(1000): s1 = ''.join([random.choice(string.hexdigits) for j in xrange(16)]) s2 = ''.join([random.choice(string.letters) for j in xrange(200)]) testdata.append((s1, s2)) init_testdata() def insert_mongo(): for s1, s2 in testdata: coll.insert({'_id': s1, 'content': s2}) def find_mongo(): for s1, s2 in testdata: s = coll.find_one({'_id': s1}) def testfunc(funcname, times=1000): from timeit import Timer t = Timer("%s()" % funcname, "from __main__ import \*") print('funcname: %s used %f' % (funcname, t.

Nov 15, 2011 - 2 minute read - Comments

语言的易读性

何谓语言的易读性,简单来说,就是看到一段代码的时候,能够了解其意思。易读性最差的典型代表作是汇编语言和机器语言,因为在读这两种语言的时候,其实是你的大脑在替代模拟CPU的功效。说起来,自从汇编以后,每种语言多多少少都注重了人类阅读的习惯,像brainfuck这种特例是万难一见的。例如下面的例子。 printf("hello, worldn"); 即使没有任何C基础的人,也能够看懂这是在做一个字符串打印。 语言的易读性其实是语言非常重要的特征,比其他特征都重要。因为人类的大脑不可能记得所有的代码细节,并且能够直观的反应出如何修改。往往我们需要阅读一下代码,搞明白每段的意思,然后才能动手——哪怕这段代码出自自己手笔,只要过得一两个月,还是要重读一下的。正是因为读这个技能的使用频率非常高,所以语言的易读性非常直观的影响到语言的易用性。而易读性差的语言和习惯,目前来看有以下几个典型例子。 1.罗嗦 典型代表是Java。下面是一个Java解压Zip的代码,引用自参考1。 public class Zip{ static final int BUFFER=2048; public static void main(String argv[]){ try{ BufferedInputStream origin=null; FileOutputStream dest=new FileOutputStream("E:testmyfiles.zip"); ZipOutputStream out=new ZipOutputStream( new BufferedOutputStream(dest)); byte data[]=new byte[BUFFER]; Filef=new File("e:\test\a"); File files[]=f.listFiles(); for(int i=0;i<files.length;i++){ FileInputStream fi=new FileInputStream(files[i]); origin=new BufferedInputStream(fi, BUFFER); ZipEntryentry=new ZipEntry(files[i].getName()); out.putNextEntry(entry); int count; while((count=origin.read(data,0,BUFFER))!=-1){ out.write(data,0,count); } origin.close(); } out.close(); }catch(Exceptione){ e.printStackTrace(); } } } 我下面给出python版本。 import os, zipfile with zipfile.ZipFile(‘filename.zip’, ‘w’ ,zipfile.

Nov 14, 2011 - 1 minute read - Comments

NSIS在64位下安装时无法写入注册表的问题

最近公司碰到一个问题,NSIS在64位下安装时无法写入注册表。 首先,这个问题不是UAC没有权限的问题,因为我使用administrator安装依然有问题。其次,问题和win2008没关系,只出现在64位上。 问题在哪里呢?在写入注册表前,SetRegView 64,写入后换回32,问题解决。 真TMD的。

Nov 11, 2011 - 1 minute read - Comments

关于网站架构的几封邮件摘抄

Shell.Xu <shell909090@gmail.com>: 我知道,我自己写过一个greenlet + epoll的实验性框架。 http://code.google.com/p/py-web-server 最主要的问题是,写到后来我发现,这东西对用户的要求太高了。要用好这种框架,用户必须具备系统经验,知道阻塞操作实际上是由非阻塞操作和上下文调度去模拟的,知道代码处处无阻塞(其实是不能有无调度的阻塞),能够想像系统是如何运行的。 这种人不会太多。在cpyug里面不算少,抓10个20个肯定能抓出来,抓上100个也不是没希望。但是实际在操作的时候,平摊到上海这么个地方,会python的也就见过那么不到100人,有这种要求的几乎可以一个个数出来。而且大多数已经在一个不错的公司里面有个不错的职位,你没法指望招个人来做事。 这也是为什么很多公司凡python必django的原因,毕竟用了django,虽然罕见,但是可以招人。用了tornado,能招的范围就少了很多。我自己做的这个实验性的玩意,风险大不说,HR角度来说,可选程序员只有一个。一旦在上面做了系统,不废弃系统的前提下,你压根没法谈判工资。。。 从语言角度来说,我更倾向于lisp,那个比较优美一些,而且也有编译成C的选项,速度不慢,天然的fp。问题是lisp从语义的自然可理解性来说非常差劲,那个传说中某AI实验室源码最后一页全是)并非空穴来风。对于新手入门而言,lisp成本更加高,使用lisp做系统,HR执行的难度也更高。haskell我并不懂,不过从语言理解来说,大概介于lisp和python之间吧。 协程型框架和进程/线程型框架相比,最大的好处就是减少了锁的问题。因为上下文切换的位置都是已知的,是否需要锁很容易考虑。很多时候甚至不需要严格锁定,只要置标志位就好,速度很快。使用fp,也可以大幅减少锁的问题,但绝对不是避免。目前的系统架构设计,已经越来越多的把锁的问题扔到了数据库层。 例如,我在操作一条记录的时候,一定会发生行级锁,否则就是不安全的。而在添加一条记录的时候,必然会修改这个表上关联的索引。而修改索引的瞬间,就会发生瞬时的锁定和解锁,否则也是不安全的。这个过程虽然对用户不可见,但是并非不存在。诚然,数据库访问是基于网络的,而基于网络的read是一个阻塞操作,在架构级别一定会调度到别的上下文执行。但是没意义阿,大规模的用户访问,除掉可以缓存的部分外,都被压到了数据库上进行读写。这些访问,在表级频繁的发生冲突,被各种锁序列化成顺序访问。到最后,我们不断的向系统中添加机器,来换取性能增长的时候,应用服务器实际上变成了问题最小的一个——小到用也许bash去写cgi都可以满足。与此同时,我们的数据库问题越来越大,还没法拆分——你没办法像应用服务器负载均衡那样把数据库拆到多个机器上去,然后让他们的写入性能成倍数增加。 无论是mongo,redis,还是mysql,都没有本质上的解决锁,尤其是写入锁的问题。mongo的读取性能可以上到15kreq/s,但是写入只有5kreq/s,而且好像还不能由sheding做加速——至少不是成倍级别的加速。mysql目前比较成熟的方案还是单写多读。当然,还有所谓水平拆分和垂直拆分的方法。垂直拆分对业务有要求,水平拆分只解决了大规模数据吞吐分布到多个存储媒体的问题,不解决索引访问的问题。redis压根没有自己的分布方案,你必须自己来做。 k-v受到热捧的原因之一,在它给了你一个从某个层面绕过这个问题的方法。目前写入锁最严重的点在于索引。无论是插入还是修改记录都需要在数据库上变更索引,而索引的变更就必然会发生锁。K-V的要点在于不允许在记录上做索引——所以mongo不是k-v数据库——从而允许用户将庞大的写操作分布到数十乃至数百台机器上的同时,获得倍数级别的性能增长。我们先不考虑添加/删除——这个是一致性哈希的目标,也不考虑可用性——这个是冗余的目标。仅从这点来说,k-v数据库受到热捧是有原因的。 问题是,这也不是解决问题,这只是绕过问题。相信使用k-v的人应该有所感受,这玩意根本没法替代常规数据库来用。没有事务,没有一致性隔离就算了。连索引都没有,这TMD的怎么用阿。目前来说,更加实际的使用还是用k-v来存储一些确实没必要进行索引的东西——例如大量小规模图片,用户的属性数据。 Zoom.Quiet <zoom.quiet@gmail.com>: 那么这样的话,可以考虑用 Erlang ,这货天然就是为了大分布高迸发服务发明的 而且从语义行文角度看也很好理解 更加要命的是 erl 提供了丰富到变态的动态调试工具,风骚无比的热部署无缝回滚… 只是,摧悲的是 erl 对于计算无爱… 不过,反过来想一下: 现在 web2.0 的世界,以及在爆发中的移动互联应用中,有什么是非要复杂关系查询的?! 通过业务的良好统计,可以从业务角度就异步化 那么,不论什么语言来开发,都没有阻塞问题存在了哈… 这也是为毛 K/V 数据库得以商业应用的主要原因 另外,前述有人说 git 作存儲的思路也是个方向: 既然分布式写入锁是个难题 那么就直接只进行本地操作好了 仅在必要时,进行分布式合并,这方面,各种版本控制系统都作得很好 如果 redis 的bilog 文本对 git 合并是可耐受的,那不就是个山寨的分布异步安全锁了? Shell.Xu <shell909090@gmail.com>:

Nov 10, 2011 - 1 minute read - Comments

openwrt配置——自动重启openvpn

还记得如何配置openvpn么?手工配置有个问题,当我ppp0连接断掉,需要重启路由器的时候,网络会短暂的断开。然后,openvpn就失效了,导致各种混乱后果。为了解决这个问题,我测试了一下,做了以下设置。 -----/etc/hotplug.d/iface/30-openvpn----- #!/bin/sh [ "$ACTION" = "ifup" -a "$INTERFACE" = "wan" ] && [ -z "`/sbin/ifconfig tun0 2>&1 | grep inet`" ] && { /etc/init.d/openvpn start } [ "$ACTION" = "ifdown" -a "$INTERFACE" = "wan" ] && [ -n "`/sbin/ifconfig tun0 2>&1 | grep inet`" ] && { /etc/init.d/openvpn stop } -----end files----- 好了,你重启外网连接的时候,就会自动连接openvpn。 参考: OpenWRT下的动态DNS(用3322.org的服务)

Nov 9, 2011 - 2 minute read - Comments

几个模板系统的性能对比

对比目标,jinja2,cheetah,mako,webpy,bottle,tornado,django的性能。  方法,随机生成一个二维数组,第一列是自增数据,第二列是长度为100的随机字符串,然后生成html,比较一次生成的时间。 说明,如果模板有编译缓存,打开。有其他方法加速,打开。生成缓存,关闭。不计算随机数据生成时间,一次生成后一直使用。 以下是文件有效内容,没用的都略去了。最后的顺序是因为我根据结果整理了一下调用次序。 -----testcheetah.tmpl----- <table> \#for \$i in \$l <tr> <td>\$i\[0\]</td> <td>\$i\[1\]</td> </tr> \#end for </table> -----testdjango.html----- <table> {% for i in l %} <tr> <td>{{ i.0 }}</td> <td>{{ i.1 }}</td> </tr> {% endfor %} </table>