<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title type="text">博客园_lulu Studio</title><subtitle type="text">我的Flash站</subtitle><id>http://feed.cnblogs.com/blog/u/30181/rss</id><updated>2012-03-31T15:48:08Z</updated><author><name>Q.Lee.lulu</name><uri>http://www.cnblogs.com/QLeelulu/</uri></author><generator>feed.cnblogs.com</generator><link rel="alternate" type="text/html" href="http://www.cnblogs.com/QLeelulu/"/><link rel="self" type="application/atom+xml" href="http://feed.cnblogs.com/blog/u/30181/rss"/><entry><id>http://www.cnblogs.com/QLeelulu/archive/2012/02/08/2343260.html</id><title type="text">用OpenCv来做人脸识别</title><summary type="text">参考这篇文章：http://tech.idv2.com/2012/01/20/face-detection-with-python-opencv/python比较简单，只需安装 python-opencv 就行：$ sudo apt-get install python-opencvpython的实现也很简单，参考：http://opencv.willowgarage.com/documentation/python/objdetect_cascade_classification.html代码：#!/usr/bin/python# -*- coding: UTF-8 -*-# face_de</summary><published>2012-02-08T14:10:00Z</published><updated>2012-02-08T14:10:00Z</updated><author><name>Q.Lee.lulu</name><uri>http://www.cnblogs.com/QLeelulu/</uri></author><link rel="alternate" href="http://www.cnblogs.com/QLeelulu/archive/2012/02/08/2343260.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/QLeelulu/archive/2012/02/08/2343260.html"/><content type="html">&lt;p&gt;参考这篇文章：&amp;nbsp;&lt;a href="http://tech.idv2.com/2012/01/20/face-detection-with-python-opencv/"&gt;http://tech.idv2.com/2012/01/20/face-detection-with-python-opencv/&lt;/a&gt;&lt;/p&gt;&lt;p&gt;python比较简单，只需安装 python-opencv 就行：&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;$ sudo apt-get install python-opencv&lt;/div&gt;&lt;p&gt;python的实现也很简单，参考：&lt;a href="http://opencv.willowgarage.com/documentation/python/objdetect_cascade_classification.html"&gt;http://opencv.willowgarage.com/documentation/python/objdetect_cascade_classification.html&lt;/a&gt;&lt;/p&gt;&lt;p&gt;代码：&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;&lt;span style="color: #008000;"&gt;#&lt;/span&gt;&lt;span style="color: #008000;"&gt;!/usr/bin/python&lt;/span&gt;&lt;span style="color: #008000;"&gt;&lt;br /&gt;#&lt;/span&gt;&lt;span style="color: #008000;"&gt; -*- coding: UTF-8 -*-&lt;/span&gt;&lt;span style="color: #008000;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;#&lt;/span&gt;&lt;span style="color: #008000;"&gt; face_detect.py&lt;/span&gt;&lt;span style="color: #008000;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;#&lt;/span&gt;&lt;span style="color: #008000;"&gt; Face Detection using OpenCV. Based on sample code from:&lt;/span&gt;&lt;span style="color: #008000;"&gt;&lt;br /&gt;#&lt;/span&gt;&lt;span style="color: #008000;"&gt; http://python.pastebin.com/m76db1d6b&lt;/span&gt;&lt;span style="color: #008000;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008000;"&gt;#&lt;/span&gt;&lt;span style="color: #008000;"&gt; Usage: python face_detect.py &amp;lt;image_file&amp;gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000ff;"&gt;import&lt;/span&gt; sys, os&lt;br /&gt;&lt;span style="color: #0000ff;"&gt;import&lt;/span&gt; cv&lt;br /&gt;&lt;span style="color: #0000ff;"&gt;from&lt;/span&gt; PIL &lt;span style="color: #0000ff;"&gt;import&lt;/span&gt; Image, ImageDraw&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #0000ff;"&gt;def&lt;/span&gt; detectObjects(image):&lt;br /&gt;    &lt;span style="color: #800000;"&gt;"""&lt;/span&gt;&lt;span style="color: #800000;"&gt;Converts an image to grayscale and prints the locations of any faces found&lt;/span&gt;&lt;span style="color: #800000;"&gt;"""&lt;/span&gt;&lt;br /&gt;    storage = cv.CreateMemStorage()&lt;br /&gt;&lt;br /&gt;    cascade = cv.Load(&lt;span style="color: #800000;"&gt;'&lt;/span&gt;&lt;span style="color: #800000;"&gt;haarcascade_frontalface_alt.xml&lt;/span&gt;&lt;span style="color: #800000;"&gt;'&lt;/span&gt;)&lt;br /&gt;    faces = cv.HaarDetectObjects(image, cascade, storage)&lt;br /&gt;&lt;br /&gt;    result = []&lt;br /&gt;    &lt;span style="color: #0000ff;"&gt;for&lt;/span&gt; (x,y,w,h),n &lt;span style="color: #0000ff;"&gt;in&lt;/span&gt; faces:&lt;br /&gt;        result.append((x, y, x+w, y+h))&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: #0000ff;"&gt;return&lt;/span&gt; result&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #0000ff;"&gt;def&lt;/span&gt; process(infile, outfile):&lt;br /&gt;&lt;br /&gt;    image = cv.LoadImage(infile);&lt;br /&gt;    &lt;span style="color: #0000ff;"&gt;if&lt;/span&gt; image:&lt;br /&gt;        faces = detectObjects(image)&lt;br /&gt;&lt;br /&gt;    im = Image.open(infile)&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: #0000ff;"&gt;if&lt;/span&gt; faces:&lt;br /&gt;        draw = ImageDraw.Draw(im)&lt;br /&gt;        &lt;span style="color: #0000ff;"&gt;for&lt;/span&gt; f &lt;span style="color: #0000ff;"&gt;in&lt;/span&gt; faces:&lt;br /&gt;            draw.rectangle(f, outline=(255, 0, 255))&lt;br /&gt;&lt;br /&gt;        im.save(outfile, &lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #800000;"&gt;JPEG&lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;, quality=100)&lt;br /&gt;    &lt;span style="color: #0000ff;"&gt;else&lt;/span&gt;:&lt;br /&gt;        &lt;span style="color: #0000ff;"&gt;print&lt;/span&gt; &lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #800000;"&gt;Error: cannot detect faces on %s&lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt; % infile&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #0000ff;"&gt;if&lt;/span&gt; &lt;span style="color: #800080;"&gt;__name__&lt;/span&gt; == &lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #800000;"&gt;__main__&lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;:&lt;br /&gt;    process(&lt;span style="color: #800000;"&gt;'&lt;/span&gt;&lt;span style="color: #800000;"&gt;input.jpg&lt;/span&gt;&lt;span style="color: #800000;"&gt;'&lt;/span&gt;, &lt;span style="color: #800000;"&gt;'&lt;/span&gt;&lt;span style="color: #800000;"&gt;output.jpg&lt;/span&gt;&lt;span style="color: #800000;"&gt;'&lt;/span&gt;)&lt;/div&gt;&lt;p&gt;注：&lt;span data-mce-=""&gt;haarcascade_frontalface_alt.xml &lt;/span&gt;可以在 &lt;a href="https://github.com/talvarez/Face.js/tree/master/cascades" target="_blank"&gt;https://github.com/talvarez/Face.js/tree/master/cascades&lt;/a&gt;&amp;nbsp;找到&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;Node.js的话，有一个叫Face.js的项目，对OpenCv做了简单封装，地址是：&amp;nbsp;&lt;a href="https://github.com/talvarez/Face.js" target="_blank"&gt;https://github.com/talvarez/Face.js&lt;/a&gt;&amp;nbsp;&lt;br /&gt;这个需要先安装OpenCv库，目前版本是2.3.1，按照可以参考：&amp;nbsp;&lt;a id="cb_post_title_url" class="postTitle2" href="http://www.cnblogs.com/JohnShao/archive/2011/09/22/2184653.html"&gt;UBUNTU 下编译安装opencv 2.3.1&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Face.js的具体的示例代码可以在Face.js里面的&lt;a href="https://github.com/talvarez/Face.js/tree/master/examples" target="_blank"&gt;example&lt;/a&gt;里面找到，这里贴个简单的：&amp;nbsp;&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;&lt;span style="color: #0000ff;"&gt;var&lt;/span&gt; Face = require('../build/default/face.node'),&lt;br /&gt;  detector = &lt;span style="color: #0000ff;"&gt;new&lt;/span&gt; Face.init();&lt;br /&gt;&lt;br /&gt;detector.img = './samples/frame1.png';&lt;br /&gt;detector.maxsize = 20;&lt;br /&gt;detector.pathto = '../cascades/'&lt;br /&gt;&lt;br /&gt;detector.oncomplete = &lt;span style="color: #0000ff;"&gt;function&lt;/span&gt;(faces){&lt;br /&gt;  console.log("I found " + faces.length + " faces");&lt;br /&gt;    &lt;span style="color: #0000ff;"&gt;for&lt;/span&gt;(&lt;span style="color: #0000ff;"&gt;var&lt;/span&gt; i = 0; i &amp;lt; faces.length; i++) {&lt;br /&gt;    console.log(faces[i].x, faces[i].y, faces[i].width, faces[i].height);&lt;br /&gt;  }&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;detector.run();&lt;/div&gt;&lt;p&gt;&lt;br /&gt;最后贴张识别后的图：&lt;/p&gt;&lt;p&gt;&lt;img src="http://pic002.cnblogs.com/images/2012/26621/2012020822082379.jpg" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/QLeelulu/aggbug/2343260.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/QLeelulu/archive/2012/02/08/2343260.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/QLeelulu/archive/2011/12/30/2308084.html</id><title type="text">linux下SublimeText的中文输入法问题之解决方案</title><summary type="text">推荐使用dev版：http://www.sublimetext.com/dev先说说中文显示的问题：找一个支持中文显示的字体，然后修改配置 Preference - File Settings - user:{"font_face": "DejaVu Sans YuanTi Mono"}注：只能改user的，改Default的没效的。Sublime Text的中文输入问题，困扰了我好久，今天终于在Zoom.Quiet周大妈的提点下，无意间搞掂了。装scim什么的就不说了，推荐安装scim-googlepinyin 。装好了配置是关键，在“系统－语言支持</summary><published>2011-12-30T14:31:00Z</published><updated>2011-12-30T14:31:00Z</updated><author><name>Q.Lee.lulu</name><uri>http://www.cnblogs.com/QLeelulu/</uri></author><link rel="alternate" href="http://www.cnblogs.com/QLeelulu/archive/2011/12/30/2308084.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/QLeelulu/archive/2011/12/30/2308084.html"/><content type="html">&lt;p&gt;推荐使用dev版：&amp;nbsp;&lt;a href="http://www.sublimetext.com/dev"&gt;http://www.sublimetext.com/dev&lt;/a&gt;&lt;/p&gt;&lt;p&gt;先说说&lt;strong&gt;中文显示&lt;/strong&gt;的问题：&lt;/p&gt;&lt;p&gt;找一个支持中文显示的字体，然后修改配置 Preference - File Settings - user:&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;{&lt;br/&gt;"font_face": "DejaVu Sans YuanTi Mono"&lt;br/&gt;}&lt;br/&gt;&lt;/div&gt;&lt;p&gt;注：只能改user的，改Default的没效的。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;Sublime Text的中文输入问题，困扰了我好久，今天终于在Zoom.Quiet周大妈的提点下，无意间搞掂了。&lt;/p&gt;&lt;p&gt;装scim什么的就不说了，推荐安装&amp;nbsp;scim-googlepinyin 。&lt;/p&gt;&lt;p&gt;装好了配置是关键，在&amp;ldquo;系统－语言支持&amp;rdquo;里面选上&amp;ldquo;&lt;span style="color: #ff0000;"&gt;scim-bridge&lt;/span&gt;&amp;rdquo;就可以了（选scim是不行的）。&lt;br /&gt;或者命令&amp;ldquo; sudo im-switch -s scim-bridge -z default&amp;nbsp;&amp;rdquo;也可以？(没测试)&amp;nbsp;&lt;/p&gt;&lt;p&gt;就这样，哦了！！&lt;/p&gt;&lt;p&gt;&lt;span style="color: #008000;"&gt;附scim输入框不能跟随问题解决办法：&lt;/span&gt;&lt;/p&gt;&lt;p&gt;将默认的 GTK_IM_MODULE=scim 修改为 GTK_IM_MODULE="scim-bridge"。保存退出.&lt;/p&gt;&lt;p&gt;在scim输入法中进行了如下设定：&lt;/p&gt;&lt;p&gt;scim设置－&amp;gt;全局设置－&amp;gt;将预编辑字符串嵌入到客户端中 前的勾去掉&lt;/p&gt;&lt;p&gt;scim设置-&amp;gt;gtk-&amp;gt;嵌入式候选词标的勾去掉&lt;/p&gt;&lt;p&gt;重启scim&lt;/p&gt;&lt;p&gt;打开终端,输入 pkill scim&lt;/p&gt;&lt;p&gt;然后输入 scim -d&lt;/p&gt;&lt;p&gt;不行的话注销一下试试。（在sublimetext中还是不能跟随光标）&lt;/p&gt;&lt;p&gt;OK。&lt;/p&gt;&lt;img src="http://www.cnblogs.com/QLeelulu/aggbug/2308084.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/QLeelulu/archive/2011/12/30/2308084.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/QLeelulu/archive/2011/09/07/2170204.html</id><title type="text">golang与node.js的http对比测试</title><summary type="text">听说Go是很不错的语言，了解了一下，一些特性确实很不错。顺便测试了一下http与node.js的性能对比。go的代码： （注：是用8g, 8l编译的）node.js的代码：ab测试结果：==** GO **==$ ab -c 100 -n 1000 http://127.0.0.1:8080/This is ApacheBench, Version 2.3 &lt;$Revision: 655654 $&gt;Server Software: Server Hostname: 127.0.0.1Server Port: 8080Document Path:...</summary><published>2011-09-07T11:46:00Z</published><updated>2011-09-07T11:46:00Z</updated><author><name>Q.Lee.lulu</name><uri>http://www.cnblogs.com/QLeelulu/</uri></author><link rel="alternate" href="http://www.cnblogs.com/QLeelulu/archive/2011/09/07/2170204.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/QLeelulu/archive/2011/09/07/2170204.html"/><content type="html">&lt;p&gt;听说Go是很不错的语言，了解了一下，一些特性确实很不错。&lt;/p&gt;&lt;p&gt;顺便测试了一下http与node.js的性能对比。&lt;/p&gt;&lt;p&gt;go的代码：&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/QLeelulu/201109/201109071946284223.png"&gt;&lt;img style="display: inline; border: 0px;" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/QLeelulu/201109/201109071946288401.png" width="417" height="221" /&gt;&lt;/a&gt; &lt;br /&gt;（注：是用8g, 8l编译的）&lt;/p&gt;&lt;p&gt;node.js的代码：&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/QLeelulu/201109/201109071946283417.png"&gt;&lt;img style="display: inline; border: 0px;" title="image" border="0" alt="image" src="http://images.cnblogs.com/cnblogs_com/QLeelulu/201109/201109071946285402.png" width="420" height="103" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;ab测试结果：&lt;/p&gt;&lt;p&gt;==** GO **==&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;&lt;span style="color: #000000;"&gt;$&lt;/span&gt;&lt;span style="color: #000000;"&gt; ab -c &lt;/span&gt;&lt;span style="color: #000000;"&gt;100&lt;/span&gt;&lt;span style="color: #000000;"&gt; -n &lt;/span&gt;&lt;span style="color: #000000;"&gt;1000&lt;/span&gt;&lt;span style="color: #000000;"&gt; http:&lt;/span&gt;&lt;span style="color: #000000;"&gt;//&lt;/span&gt;&lt;span style="color: #000000;"&gt;127.0&lt;/span&gt;&lt;span style="color: #000000;"&gt;.&lt;/span&gt;&lt;span style="color: #000000;"&gt;0.1&lt;/span&gt;&lt;span style="color: #000000;"&gt;:&lt;/span&gt;&lt;span style="color: #000000;"&gt;8080&lt;/span&gt;&lt;span style="color: #000000;"&gt;/&lt;/span&gt;&lt;span style="color: #000000;"&gt;&lt;br /&gt;This is ApacheBench&lt;/span&gt;&lt;span style="color: #000000;"&gt;,&lt;/span&gt;&lt;span style="color: #000000;"&gt; Version &lt;/span&gt;&lt;span style="color: #000000;"&gt;2.3&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;lt;$&lt;/span&gt;&lt;span style="color: #000000;"&gt;Revision: &lt;/span&gt;&lt;span style="color: #000000;"&gt;655654&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #000000;"&gt;$&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;&lt;br /&gt;&lt;br /&gt;Server Software:        &lt;br /&gt;Server Hostname:        &lt;/span&gt;&lt;span style="color: #000000;"&gt;127.0&lt;/span&gt;&lt;span style="color: #000000;"&gt;.&lt;/span&gt;&lt;span style="color: #000000;"&gt;0.1&lt;/span&gt;&lt;span style="color: #000000;"&gt;&lt;br /&gt;Server Port:            &lt;/span&gt;&lt;span style="color: #000000;"&gt;8080&lt;/span&gt;&lt;span style="color: #000000;"&gt;&lt;br /&gt;&lt;br /&gt;Document &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;Path&lt;/span&gt;&lt;span style="color: #000000;"&gt;:          &lt;/span&gt;&lt;span style="color: #000000;"&gt;/&lt;/span&gt;&lt;span style="color: #000000;"&gt;&lt;br /&gt;Document Length:        &lt;/span&gt;&lt;span style="color: #000000;"&gt;1&lt;/span&gt;&lt;span style="color: #000000;"&gt; bytes&lt;br /&gt;&lt;br /&gt;Concurrency Level:      &lt;/span&gt;&lt;span style="color: #000000;"&gt;100&lt;/span&gt;&lt;span style="color: #000000;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;Time&lt;/span&gt;&lt;span style="color: #000000;"&gt; taken &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;for&lt;/span&gt;&lt;span style="color: #000000;"&gt; tests:   &lt;/span&gt;&lt;span style="color: #000000;"&gt;0.322&lt;/span&gt;&lt;span style="color: #000000;"&gt; seconds&lt;br /&gt;Complete requests:      &lt;/span&gt;&lt;span style="color: #000000;"&gt;1000&lt;/span&gt;&lt;span style="color: #000000;"&gt;&lt;br /&gt;Failed requests:        &lt;/span&gt;&lt;span style="color: #000000;"&gt;0&lt;/span&gt;&lt;span style="color: #000000;"&gt;&lt;br /&gt;Write errors:           &lt;/span&gt;&lt;span style="color: #000000;"&gt;0&lt;/span&gt;&lt;span style="color: #000000;"&gt;&lt;br /&gt;Total transferred:      &lt;/span&gt;&lt;span style="color: #000000;"&gt;97000&lt;/span&gt;&lt;span style="color: #000000;"&gt; bytes&lt;br /&gt;HTML transferred:       &lt;/span&gt;&lt;span style="color: #000000;"&gt;1000&lt;/span&gt;&lt;span style="color: #000000;"&gt; bytes&lt;br /&gt;Requests per second:    &lt;/span&gt;&lt;strong&gt;&lt;span style="color: #ff0000;"&gt;3105.62 [#/sec] &lt;/span&gt;&lt;/strong&gt;&lt;span style="color: #000000;"&gt;(&lt;/span&gt;&lt;span style="color: #000000;"&gt;mean&lt;/span&gt;&lt;span style="color: #000000;"&gt;)&lt;/span&gt;&lt;span style="color: #000000;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;Time&lt;/span&gt;&lt;span style="color: #000000;"&gt; per request:       &lt;/span&gt;&lt;span style="color: #000000;"&gt;32.200&lt;/span&gt;&lt;span style="color: #000000;"&gt; [ms] &lt;/span&gt;&lt;span style="color: #000000;"&gt;(&lt;/span&gt;&lt;span style="color: #000000;"&gt;mean&lt;/span&gt;&lt;span style="color: #000000;"&gt;)&lt;/span&gt;&lt;span style="color: #000000;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;Time&lt;/span&gt;&lt;span style="color: #000000;"&gt; per request:       &lt;/span&gt;&lt;span style="color: #000000;"&gt;0.322&lt;/span&gt;&lt;span style="color: #000000;"&gt; [ms] &lt;/span&gt;&lt;span style="color: #000000;"&gt;(&lt;/span&gt;&lt;span style="color: #000000;"&gt;mean&lt;/span&gt;&lt;span style="color: #000000;"&gt;,&lt;/span&gt;&lt;span style="color: #000000;"&gt; across all concurrent requests&lt;/span&gt;&lt;span style="color: #000000;"&gt;)&lt;/span&gt;&lt;span style="color: #000000;"&gt;&lt;br /&gt;Transfer rate:          &lt;/span&gt;&lt;span style="color: #000000;"&gt;294.18&lt;/span&gt;&lt;span style="color: #000000;"&gt; [Kbytes&lt;/span&gt;&lt;span style="color: #000000;"&gt;/&lt;/span&gt;&lt;span style="color: #000000;"&gt;sec] received&lt;br /&gt;&lt;br /&gt;Connection Times &lt;/span&gt;&lt;span style="color: #000000;"&gt;(&lt;/span&gt;&lt;span style="color: #000000;"&gt;ms&lt;/span&gt;&lt;span style="color: #000000;"&gt;)&lt;/span&gt;&lt;span style="color: #000000;"&gt;&lt;br /&gt;              min  mean[&lt;/span&gt;&lt;span style="color: #000000;"&gt;+/&lt;/span&gt;&lt;span style="color: #000000;"&gt;-sd] median   max&lt;br /&gt;Connect:        &lt;/span&gt;&lt;span style="color: #000000;"&gt;0&lt;/span&gt;&lt;span style="color: #000000;"&gt;    &lt;/span&gt;&lt;span style="color: #000000;"&gt;0&lt;/span&gt;&lt;span style="color: #000000;"&gt;   &lt;/span&gt;&lt;span style="color: #000000;"&gt;0.7&lt;/span&gt;&lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #000000;"&gt;0&lt;/span&gt;&lt;span style="color: #000000;"&gt;       &lt;/span&gt;&lt;span style="color: #000000;"&gt;3&lt;/span&gt;&lt;span style="color: #000000;"&gt;&lt;br /&gt;Processing:     &lt;/span&gt;&lt;span style="color: #000000;"&gt;1&lt;/span&gt;&lt;span style="color: #000000;"&gt;   &lt;/span&gt;&lt;span style="color: #000000;"&gt;30&lt;/span&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #000000;"&gt;10.5&lt;/span&gt;&lt;span style="color: #000000;"&gt;     &lt;/span&gt;&lt;span style="color: #000000;"&gt;29&lt;/span&gt;&lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #000000;"&gt;55&lt;/span&gt;&lt;span style="color: #000000;"&gt;&lt;br /&gt;Waiting:        &lt;/span&gt;&lt;span style="color: #000000;"&gt;1&lt;/span&gt;&lt;span style="color: #000000;"&gt;   &lt;/span&gt;&lt;span style="color: #000000;"&gt;30&lt;/span&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #000000;"&gt;10.5&lt;/span&gt;&lt;span style="color: #000000;"&gt;     &lt;/span&gt;&lt;span style="color: #000000;"&gt;29&lt;/span&gt;&lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #000000;"&gt;55&lt;/span&gt;&lt;span style="color: #000000;"&gt;&lt;br /&gt;Total:          &lt;/span&gt;&lt;span style="color: #000000;"&gt;4&lt;/span&gt;&lt;span style="color: #000000;"&gt;   &lt;/span&gt;&lt;span style="color: #000000;"&gt;30&lt;/span&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #000000;"&gt;10.1&lt;/span&gt;&lt;span style="color: #000000;"&gt;     &lt;/span&gt;&lt;span style="color: #000000;"&gt;29&lt;/span&gt;&lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #000000;"&gt;55&lt;/span&gt;&lt;/div&gt;&lt;p&gt;==** Node.js **==&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;&lt;span style="color: #000000;"&gt;$&lt;/span&gt;&lt;span style="color: #000000;"&gt; ab -c &lt;/span&gt;&lt;span style="color: #000000;"&gt;100&lt;/span&gt;&lt;span style="color: #000000;"&gt; -n &lt;/span&gt;&lt;span style="color: #000000;"&gt;1000&lt;/span&gt;&lt;span style="color: #000000;"&gt; http:&lt;/span&gt;&lt;span style="color: #000000;"&gt;//&lt;/span&gt;&lt;span style="color: #000000;"&gt;127.0&lt;/span&gt;&lt;span style="color: #000000;"&gt;.&lt;/span&gt;&lt;span style="color: #000000;"&gt;0.1&lt;/span&gt;&lt;span style="color: #000000;"&gt;:&lt;/span&gt;&lt;span style="color: #000000;"&gt;8080&lt;/span&gt;&lt;span style="color: #000000;"&gt;/&lt;/span&gt;&lt;span style="color: #000000;"&gt;&lt;br /&gt;This is ApacheBench&lt;/span&gt;&lt;span style="color: #000000;"&gt;,&lt;/span&gt;&lt;span style="color: #000000;"&gt; Version &lt;/span&gt;&lt;span style="color: #000000;"&gt;2.3&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;lt;$&lt;/span&gt;&lt;span style="color: #000000;"&gt;Revision: &lt;/span&gt;&lt;span style="color: #000000;"&gt;655654&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #000000;"&gt;$&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;&lt;br /&gt;&lt;br /&gt;Server Software:        &lt;br /&gt;Server Hostname:        &lt;/span&gt;&lt;span style="color: #000000;"&gt;127.0&lt;/span&gt;&lt;span style="color: #000000;"&gt;.&lt;/span&gt;&lt;span style="color: #000000;"&gt;0.1&lt;/span&gt;&lt;span style="color: #000000;"&gt;&lt;br /&gt;Server Port:            &lt;/span&gt;&lt;span style="color: #000000;"&gt;8080&lt;/span&gt;&lt;span style="color: #000000;"&gt;&lt;br /&gt;&lt;br /&gt;Document &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;Path&lt;/span&gt;&lt;span style="color: #000000;"&gt;:          &lt;/span&gt;&lt;span style="color: #000000;"&gt;/&lt;/span&gt;&lt;span style="color: #000000;"&gt;&lt;br /&gt;Document Length:        &lt;/span&gt;&lt;span style="color: #000000;"&gt;12&lt;/span&gt;&lt;span style="color: #000000;"&gt; bytes&lt;br /&gt;&lt;br /&gt;Concurrency Level:      &lt;/span&gt;&lt;span style="color: #000000;"&gt;100&lt;/span&gt;&lt;span style="color: #000000;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;Time&lt;/span&gt;&lt;span style="color: #000000;"&gt; taken &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;for&lt;/span&gt;&lt;span style="color: #000000;"&gt; tests:   &lt;/span&gt;&lt;span style="color: #000000;"&gt;0.143&lt;/span&gt;&lt;span style="color: #000000;"&gt; seconds&lt;br /&gt;Complete requests:      &lt;/span&gt;&lt;span style="color: #000000;"&gt;1000&lt;/span&gt;&lt;span style="color: #000000;"&gt;&lt;br /&gt;Failed requests:        &lt;/span&gt;&lt;span style="color: #000000;"&gt;0&lt;/span&gt;&lt;span style="color: #000000;"&gt;&lt;br /&gt;Write errors:           &lt;/span&gt;&lt;span style="color: #000000;"&gt;0&lt;/span&gt;&lt;span style="color: #000000;"&gt;&lt;br /&gt;Total transferred:      &lt;/span&gt;&lt;span style="color: #000000;"&gt;50000&lt;/span&gt;&lt;span style="color: #000000;"&gt; bytes&lt;br /&gt;HTML transferred:       &lt;/span&gt;&lt;span style="color: #000000;"&gt;12000&lt;/span&gt;&lt;span style="color: #000000;"&gt; bytes&lt;br /&gt;Requests per second:    &lt;/span&gt;&lt;strong&gt;&lt;span style="color: #ff0000;"&gt;6993.50 [#/sec] &lt;/span&gt;&lt;/strong&gt;&lt;span style="color: #000000;"&gt;(&lt;/span&gt;&lt;span style="color: #000000;"&gt;mean&lt;/span&gt;&lt;span style="color: #000000;"&gt;)&lt;/span&gt;&lt;span style="color: #000000;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;Time&lt;/span&gt;&lt;span style="color: #000000;"&gt; per request:       &lt;/span&gt;&lt;span style="color: #000000;"&gt;14.299&lt;/span&gt;&lt;span style="color: #000000;"&gt; [ms] &lt;/span&gt;&lt;span style="color: #000000;"&gt;(&lt;/span&gt;&lt;span style="color: #000000;"&gt;mean&lt;/span&gt;&lt;span style="color: #000000;"&gt;)&lt;/span&gt;&lt;span style="color: #000000;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;Time&lt;/span&gt;&lt;span style="color: #000000;"&gt; per request:       &lt;/span&gt;&lt;span style="color: #000000;"&gt;0.143&lt;/span&gt;&lt;span style="color: #000000;"&gt; [ms] &lt;/span&gt;&lt;span style="color: #000000;"&gt;(&lt;/span&gt;&lt;span style="color: #000000;"&gt;mean&lt;/span&gt;&lt;span style="color: #000000;"&gt;,&lt;/span&gt;&lt;span style="color: #000000;"&gt; across all concurrent requests&lt;/span&gt;&lt;span style="color: #000000;"&gt;)&lt;/span&gt;&lt;span style="color: #000000;"&gt;&lt;br /&gt;Transfer rate:          &lt;/span&gt;&lt;span style="color: #000000;"&gt;341.48&lt;/span&gt;&lt;span style="color: #000000;"&gt; [Kbytes&lt;/span&gt;&lt;span style="color: #000000;"&gt;/&lt;/span&gt;&lt;span style="color: #000000;"&gt;sec] received&lt;br /&gt;&lt;br /&gt;Connection Times &lt;/span&gt;&lt;span style="color: #000000;"&gt;(&lt;/span&gt;&lt;span style="color: #000000;"&gt;ms&lt;/span&gt;&lt;span style="color: #000000;"&gt;)&lt;/span&gt;&lt;span style="color: #000000;"&gt;&lt;br /&gt;              min  mean[&lt;/span&gt;&lt;span style="color: #000000;"&gt;+/&lt;/span&gt;&lt;span style="color: #000000;"&gt;-sd] median   max&lt;br /&gt;Connect:        &lt;/span&gt;&lt;span style="color: #000000;"&gt;0&lt;/span&gt;&lt;span style="color: #000000;"&gt;    &lt;/span&gt;&lt;span style="color: #000000;"&gt;0&lt;/span&gt;&lt;span style="color: #000000;"&gt;   &lt;/span&gt;&lt;span style="color: #000000;"&gt;1.1&lt;/span&gt;&lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #000000;"&gt;0&lt;/span&gt;&lt;span style="color: #000000;"&gt;       &lt;/span&gt;&lt;span style="color: #000000;"&gt;4&lt;/span&gt;&lt;span style="color: #000000;"&gt;&lt;br /&gt;Processing:     &lt;/span&gt;&lt;span style="color: #000000;"&gt;2&lt;/span&gt;&lt;span style="color: #000000;"&gt;   &lt;/span&gt;&lt;span style="color: #000000;"&gt;13&lt;/span&gt;&lt;span style="color: #000000;"&gt;   &lt;/span&gt;&lt;span style="color: #000000;"&gt;6.6&lt;/span&gt;&lt;span style="color: #000000;"&gt;     &lt;/span&gt;&lt;span style="color: #000000;"&gt;13&lt;/span&gt;&lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #000000;"&gt;30&lt;/span&gt;&lt;span style="color: #000000;"&gt;&lt;br /&gt;Waiting:        &lt;/span&gt;&lt;span style="color: #000000;"&gt;2&lt;/span&gt;&lt;span style="color: #000000;"&gt;   &lt;/span&gt;&lt;span style="color: #000000;"&gt;13&lt;/span&gt;&lt;span style="color: #000000;"&gt;   &lt;/span&gt;&lt;span style="color: #000000;"&gt;6.6&lt;/span&gt;&lt;span style="color: #000000;"&gt;     &lt;/span&gt;&lt;span style="color: #000000;"&gt;13&lt;/span&gt;&lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #000000;"&gt;30&lt;/span&gt;&lt;span style="color: #000000;"&gt;&lt;br /&gt;Total:          &lt;/span&gt;&lt;span style="color: #000000;"&gt;2&lt;/span&gt;&lt;span style="color: #000000;"&gt;   &lt;/span&gt;&lt;span style="color: #000000;"&gt;14&lt;/span&gt;&lt;span style="color: #000000;"&gt;   &lt;/span&gt;&lt;span style="color: #000000;"&gt;6.4&lt;/span&gt;&lt;span style="color: #000000;"&gt;     &lt;/span&gt;&lt;span style="color: #000000;"&gt;14&lt;/span&gt;&lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #000000;"&gt;30&lt;/span&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;webbench测试结果&lt;/p&gt;&lt;p&gt;==** GO **==&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;&lt;span style="color: #000000;"&gt;$&lt;/span&gt;&lt;span style="color: #000000;"&gt; webbench -t &lt;/span&gt;&lt;span style="color: #000000;"&gt;30&lt;/span&gt;&lt;span style="color: #000000;"&gt; -c &lt;/span&gt;&lt;span style="color: #000000;"&gt;100&lt;/span&gt;&lt;span style="color: #000000;"&gt; http:&lt;/span&gt;&lt;span style="color: #000000;"&gt;//&lt;/span&gt;&lt;span style="color: #000000;"&gt;127.0&lt;/span&gt;&lt;span style="color: #000000;"&gt;.&lt;/span&gt;&lt;span style="color: #000000;"&gt;0.1&lt;/span&gt;&lt;span style="color: #000000;"&gt;:&lt;/span&gt;&lt;span style="color: #000000;"&gt;8080&lt;/span&gt;&lt;span style="color: #000000;"&gt;/&lt;/span&gt;&lt;span style="color: #000000;"&gt;&lt;br /&gt;Webbench - Simple Web Benchmark &lt;/span&gt;&lt;span style="color: #000000;"&gt;1.5&lt;/span&gt;&lt;span style="color: #000000;"&gt;&lt;br /&gt;Copyright &lt;/span&gt;&lt;span style="color: #000000;"&gt;(&lt;/span&gt;&lt;span style="color: #000000;"&gt;c&lt;/span&gt;&lt;span style="color: #000000;"&gt;)&lt;/span&gt;&lt;span style="color: #000000;"&gt; Radim Kolar &lt;/span&gt;&lt;span style="color: #000000;"&gt;1997&lt;/span&gt;&lt;span style="color: #000000;"&gt;-&lt;/span&gt;&lt;span style="color: #000000;"&gt;2004&lt;/span&gt;&lt;span style="color: #000000;"&gt;,&lt;/span&gt;&lt;span style="color: #000000;"&gt; GPL Open Source Software&lt;/span&gt;&lt;span style="color: #000000;"&gt;.&lt;/span&gt;&lt;span style="color: #000000;"&gt;&lt;br /&gt;&lt;br /&gt;Benchmarking: GET http:&lt;/span&gt;&lt;span style="color: #000000;"&gt;//&lt;/span&gt;&lt;span style="color: #000000;"&gt;127.0&lt;/span&gt;&lt;span style="color: #000000;"&gt;.&lt;/span&gt;&lt;span style="color: #000000;"&gt;0.1&lt;/span&gt;&lt;span style="color: #000000;"&gt;:&lt;/span&gt;&lt;span style="color: #000000;"&gt;8080&lt;/span&gt;&lt;span style="color: #000000;"&gt;/&lt;/span&gt;&lt;span style="color: #000000;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;100&lt;/span&gt;&lt;span style="color: #000000;"&gt; clients&lt;/span&gt;&lt;span style="color: #000000;"&gt;,&lt;/span&gt;&lt;span style="color: #000000;"&gt; running &lt;/span&gt;&lt;span style="color: #000000;"&gt;30&lt;/span&gt;&lt;span style="color: #000000;"&gt; sec&lt;/span&gt;&lt;span style="color: #000000;"&gt;.&lt;/span&gt;&lt;span style="color: #000000;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;span style="color: #ff0000;"&gt;Speed&lt;/span&gt;&lt;/strong&gt;&lt;/span&gt;&lt;strong&gt;&lt;span style="color: #ff0000;"&gt;=146934 pages/min, 262032 bytes/sec.&lt;/span&gt;&lt;/strong&gt;&lt;span style="color: #000000;"&gt;&lt;br /&gt;Requests: &lt;/span&gt;&lt;span style="color: #000000;"&gt;73467&lt;/span&gt;&lt;span style="color: #000000;"&gt; susceed&lt;/span&gt;&lt;span style="color: #000000;"&gt;,&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #000000;"&gt;0&lt;/span&gt;&lt;span style="color: #000000;"&gt; failed&lt;/span&gt;&lt;span style="color: #000000;"&gt;.&lt;/span&gt;&lt;/div&gt;&lt;p&gt;==** Node.js **==&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;&lt;span style="color: #000000;"&gt;$&lt;/span&gt;&lt;span style="color: #000000;"&gt; webbench -t &lt;/span&gt;&lt;span style="color: #000000;"&gt;30&lt;/span&gt;&lt;span style="color: #000000;"&gt; -c &lt;/span&gt;&lt;span style="color: #000000;"&gt;100&lt;/span&gt;&lt;span style="color: #000000;"&gt; http:&lt;/span&gt;&lt;span style="color: #000000;"&gt;//&lt;/span&gt;&lt;span style="color: #000000;"&gt;127.0&lt;/span&gt;&lt;span style="color: #000000;"&gt;.&lt;/span&gt;&lt;span style="color: #000000;"&gt;0.1&lt;/span&gt;&lt;span style="color: #000000;"&gt;:&lt;/span&gt;&lt;span style="color: #000000;"&gt;8080&lt;/span&gt;&lt;span style="color: #000000;"&gt;/&lt;/span&gt;&lt;span style="color: #000000;"&gt;&lt;br /&gt;Webbench - Simple Web Benchmark &lt;/span&gt;&lt;span style="color: #000000;"&gt;1.5&lt;/span&gt;&lt;span style="color: #000000;"&gt;&lt;br /&gt;Copyright &lt;/span&gt;&lt;span style="color: #000000;"&gt;(&lt;/span&gt;&lt;span style="color: #000000;"&gt;c&lt;/span&gt;&lt;span style="color: #000000;"&gt;)&lt;/span&gt;&lt;span style="color: #000000;"&gt; Radim Kolar &lt;/span&gt;&lt;span style="color: #000000;"&gt;1997&lt;/span&gt;&lt;span style="color: #000000;"&gt;-&lt;/span&gt;&lt;span style="color: #000000;"&gt;2004&lt;/span&gt;&lt;span style="color: #000000;"&gt;,&lt;/span&gt;&lt;span style="color: #000000;"&gt; GPL Open Source Software&lt;/span&gt;&lt;span style="color: #000000;"&gt;.&lt;/span&gt;&lt;span style="color: #000000;"&gt;&lt;br /&gt;&lt;br /&gt;Benchmarking: GET http:&lt;/span&gt;&lt;span style="color: #000000;"&gt;//&lt;/span&gt;&lt;span style="color: #000000;"&gt;127.0&lt;/span&gt;&lt;span style="color: #000000;"&gt;.&lt;/span&gt;&lt;span style="color: #000000;"&gt;0.1&lt;/span&gt;&lt;span style="color: #000000;"&gt;:&lt;/span&gt;&lt;span style="color: #000000;"&gt;8080&lt;/span&gt;&lt;span style="color: #000000;"&gt;/&lt;/span&gt;&lt;span style="color: #000000;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;100&lt;/span&gt;&lt;span style="color: #000000;"&gt; clients&lt;/span&gt;&lt;span style="color: #000000;"&gt;,&lt;/span&gt;&lt;span style="color: #000000;"&gt; running &lt;/span&gt;&lt;span style="color: #000000;"&gt;30&lt;/span&gt;&lt;span style="color: #000000;"&gt; sec&lt;/span&gt;&lt;span style="color: #000000;"&gt;.&lt;/span&gt;&lt;span style="color: #000000;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;span style="color: #ff0000;"&gt;Speed&lt;/span&gt;&lt;/strong&gt;&lt;/span&gt;&lt;strong&gt;&lt;span style="color: #ff0000;"&gt;=485128 pages/min, 404273 bytes/sec.&lt;/span&gt;&lt;/strong&gt;&lt;span style="color: #000000;"&gt;&lt;br /&gt;Requests: &lt;/span&gt;&lt;span style="color: #000000;"&gt;242564&lt;/span&gt;&lt;span style="color: #000000;"&gt; susceed&lt;/span&gt;&lt;span style="color: #000000;"&gt;,&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #000000;"&gt;0&lt;/span&gt;&lt;span style="color: #000000;"&gt; failed&lt;/span&gt;&lt;span style="color: #000000;"&gt;.&lt;/span&gt;&lt;/div&gt;&lt;p&gt;从测试结果来看，node.js的HTTP SERVER性能是Go的两倍还多，而且让我比较郁闷的是，在用webbench进行测试的时候，可以看到go是用了我的笔记本上的&lt;span color="#ff0000" style="color: #ff0000;"&gt;&lt;strong&gt;四个核&lt;/strong&gt;&lt;/span&gt;的CPU的，而node.js当然是只跑在一个核上，而Go居然还比node.js慢这么多。&lt;/p&gt;&lt;p&gt;然后我google，就看到：&lt;a href="https://groups.google.com/group/golang-nuts/browse_thread/thread/cde2cc6278cefc90" target="_blank"&gt;golang helloworld 45% slower than node.js&lt;/a&gt;&lt;/p&gt;&lt;p&gt;求真相！&lt;/p&gt;&lt;img src="http://www.cnblogs.com/QLeelulu/aggbug/2170204.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/QLeelulu/archive/2011/09/07/2170204.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/QLeelulu/archive/2011/08/28/2156402.html</id><title type="text">作为Web开发人员，我为什么喜欢Google Chrome浏览器</title><summary type="text">【原文地址：http://www.cnblogs.com/QLeelulu/archive/2011/08/28/2156402.html】在Google Chrome浏览器出来之前，我一直使用FireFox，因为FireFox的插件非常丰富，更因为FireFox有强大的Firebug，对于前端开发可谓神器。在Chrome出来的时候，我就喜欢上它的简洁、快速，无论是启动速度还是页面解析速度还是Ja...</summary><published>2011-08-28T13:17:00Z</published><updated>2011-08-28T13:17:00Z</updated><author><name>Q.Lee.lulu</name><uri>http://www.cnblogs.com/QLeelulu/</uri></author><link rel="alternate" href="http://www.cnblogs.com/QLeelulu/archive/2011/08/28/2156402.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/QLeelulu/archive/2011/08/28/2156402.html"/><content type="html">&lt;p&gt;【原文地址：&lt;span class="Apple-style-span" style="color: #333333; font-family: Verdana; font-size: 13px; line-height: normal; background-color: #f5f5f5;"&gt;&lt;a id="Editor_Edit_hlEntryLink" title="view: 作为Web开发人员，我为什么喜欢Google Chrome浏览器" href="http://www.cnblogs.com/QLeelulu/archive/2011/08/28/2156402.html" target="_blank" style="color: #002c99; text-decoration: none; background: inherit;"&gt;http://www.cnblogs.com/QLeelulu/archive/2011/08/28/2156402.html&lt;/a&gt;&amp;nbsp;&lt;/span&gt;】&lt;/p&gt;&lt;p&gt;在Google Chrome浏览器出来之前，我一直使用FireFox，因为FireFox的插件非常丰富，更因为FireFox有强大的Firebug，对于前端开发可谓神器。&lt;/p&gt;&lt;p&gt;在Chrome出来的时候，我就喜欢上它的简洁、快速，无论是启动速度还是页面解析速度还是Javascript执行速度（现在的FireFox4也比之前的FireFox3有很大的进步）。不过当时由于Chrome的开发者工具还不是很完善，而我又不是很熟悉，加之对于Firebug的好感和依赖，当时还是用回FireFox作为我的主浏览器。&lt;/p&gt;&lt;p&gt;后来由于开发Chrome的插件(现在的FaWave)，就一直使用Google Chrom作为我的主浏览器，渐渐熟悉Chrome的开发者工具，而Chrome也一直在快速迭代，快速进步中，到现在，Chrome已经绝对成为我的主浏览器，Chrome的开发者工具，我也认为比Firebug更好用。&lt;/p&gt;&lt;p&gt;得益于Google V8的快速，和对HTML5和CSS3的支持也算比较完善，html类的富客户端应用Chrome上无论是流畅性还是呈现的效果，都是比较出色的，这对于开发者，特别是对于那些喜欢研究前沿技术的前端开发者来说，是很重要的。&lt;/p&gt;&lt;p&gt;对于本文，作为一个Web开发人员，除了上面的原因以外，与我们开发相关的，就是Chrome的开发者工具。而本文，就是要详细说说Chrome的开发者工具，说说我为什么认为它比Firebug要好用。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;怎样打开Chrome的开发者工具？&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;你可以直接在页面上点击右键，然后选择审查元素：&lt;br /&gt;&lt;img src="http://images.cnblogs.com/cnblogs_com/QLeelulu/201108/201108282113337336.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;或者在Chrome的工具中找到：&lt;br /&gt;&lt;img src="http://images.cnblogs.com/cnblogs_com/QLeelulu/201108/201108282113354040.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;或者，你直接记住这个快捷方式： Ctrl+Shift+I (或者Ctrl+Shift+J直接打开控制台)，或者直接按&lt;span style="color: #ff0000;"&gt;&lt;strong&gt;F12&lt;/strong&gt;&lt;/span&gt;。&lt;/p&gt;&lt;p&gt;打开的开发者工具就长下面的样子：&lt;br /&gt;&lt;img src="http://images.cnblogs.com/cnblogs_com/QLeelulu/201108/201108282113416445.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;不过我一般习惯与点左下角的那个按钮，将开发者工具弹出作为一个独立的窗口：&lt;br /&gt;&lt;img src="http://images.cnblogs.com/cnblogs_com/QLeelulu/201108/201108282113445035.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;下面来分别说下每个Tab的作用。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Elements标签页&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;这个就是查看、编辑页面上的元素，包括HTML和CSS：&lt;br /&gt;&lt;img src="http://images.cnblogs.com/cnblogs_com/QLeelulu/201108/20110828211351371.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;左侧就是对页面HTML结构的查看与编辑，你可以直接在某个元素上双击修改元素的属性，或者你点右键选"Edit as  Html"直接对元素的HTML进行编辑，或者删除某个元素，所有的修改都会即时在页面上得到呈现。（&lt;span style="color: #008000;"&gt;注：看到上面右键菜单的最后一个选项"审查元素"了么？这是不是说明这个开发者工具的页面也是HTML来的呢？你点一下就知道了哦，嘿嘿&lt;/span&gt;）&lt;br /&gt;你还可以对某个元素进行监听，在JS对元素的属性或者HTML进行修改的时候，直接触发断点，跳转到对改元素进行修改的JS代码处：&lt;br /&gt;&lt;img src="http://images.cnblogs.com/cnblogs_com/QLeelulu/201108/201108282113524176.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;Elements标签页的右侧可以对元素的CSS进行查看与编辑修改：&lt;br /&gt;&lt;img src="http://images.cnblogs.com/cnblogs_com/QLeelulu/201108/201108282113567750.png" alt="" /&gt;&lt;br /&gt;你还可以通过这里看到各CSS选择器设置的CSS值的覆盖情况。&lt;br /&gt;下面的Metrics可以看到元素占的空间情况（宽、高、Padding、Margin神马的）：&lt;br /&gt;&lt;img src="http://images.cnblogs.com/cnblogs_com/QLeelulu/201108/201108282114087542.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;注意到上面的Properties没有？这个很有用哦，可以让你看到元素具有的方法与属性，比查API手册要方便得多哦（&lt;span style="color: #ff0000;"&gt;要注意某些方法和属性在IE、FireFox等其他浏览器下面的支持情况哦&lt;/span&gt;）。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Resources标签页&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;img src="http://images.cnblogs.com/cnblogs_com/QLeelulu/201108/201108282114324650.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;Resources标签页可以查看到请求的资源情况，包括CSS、JS、图片等的内容，同时还可以查看到存储相关的如Cookies、HTML5的Database和LocalStore等，你可以对存储的内容编辑和删除。&lt;br /&gt;这里的CSS文件有一个好玩的特性，你可以直接修改CSS文件，并且修改即时生效哦：&lt;br /&gt;&lt;img src="http://images.cnblogs.com/cnblogs_com/QLeelulu/201108/201108282114522537.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Network标签页&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;img src="http://images.cnblogs.com/cnblogs_com/QLeelulu/201108/201108282115091560.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;Network标签页对于分析网站请求的网络情况、查看某一请求的请求头和响应头还有响应内容很有用，特别是在查看Ajax类请求的时候，非常有帮助。注意是在你打开Chrome开发者工具后发起的请求，才会在这里显示的哦。&lt;br /&gt;点击左侧某一个具体去请求URL，可以看到该请求的详细HTTP请求情况：&lt;/p&gt;&lt;p&gt;&lt;img src="http://images.cnblogs.com/cnblogs_com/QLeelulu/201108/201108282115168948.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;我们可以在这里看到HTTP请求头、HTTP响应头、HTTP返回的内容等信息，对于开发、调试，都是很有用的。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Scripts标签页&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;很明显，这个标签页就是查看JS文件、调试JS代码的，直接看下图的说明：&lt;/p&gt;&lt;p&gt;&lt;img src="http://images.cnblogs.com/cnblogs_com/QLeelulu/201108/201108282115301050.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;还有你可以打开Javascript控制台，做一些其他的查看或者修改：&lt;/p&gt;&lt;p&gt;&lt;img src="http://images.cnblogs.com/cnblogs_com/QLeelulu/201108/201108282115391521.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;你甚至还可以为某一XHR请求或者某一事件设置断点：&lt;/p&gt;&lt;p&gt;&lt;img src="http://images.cnblogs.com/cnblogs_com/QLeelulu/201108/201108282115406962.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Timeline标签页&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;注意这个Timeline的标签页不是指网络请求的时间响应情况哦（这个在Network标签页里查看），这个Timeline指的JS执行时间、页面元素渲染时间：&lt;/p&gt;&lt;p&gt;&lt;img src="http://images.cnblogs.com/cnblogs_com/QLeelulu/201108/20110828211544927.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;点击底部的Record就可以开始录制页面上执行的内容。（这个不熟悉，请参考文末链接）&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Profiles标签页&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;这个主要是做性能优化的，包括查看CPU执行时间与内存占用：&lt;/p&gt;&lt;p&gt;&lt;img src="http://images.cnblogs.com/cnblogs_com/QLeelulu/201108/201108282115479267.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&lt;img src="http://images.cnblogs.com/cnblogs_com/QLeelulu/201108/201108282115493430.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;这个也不熟悉，不多说，还是请参考文末链接吧。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Audits标签页&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;这个对于优化前端页面、加速网页加载速度很有用哦（相当与&lt;a href="http://developer.yahoo.com/yslow/" target="_blank"&gt;Yslow&lt;/a&gt;）：&lt;/p&gt;&lt;p&gt;&lt;img src="http://images.cnblogs.com/cnblogs_com/QLeelulu/201108/201108282115519295.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;点击run按钮，就可以开始分析页面，分析完了就可以看到分析结果了：&lt;/p&gt;&lt;p&gt;&lt;img src="http://images.cnblogs.com/cnblogs_com/QLeelulu/201108/201108282115591567.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;它甚至可以分析出页面上样式表中有哪些CSS是没有被使用的哦：&lt;/p&gt;&lt;p&gt;&lt;img src="http://images.cnblogs.com/cnblogs_com/QLeelulu/201108/201108282116163065.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Console标签页&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;就是Javascript控制台了：&lt;/p&gt;&lt;p&gt;&lt;img src="http://images.cnblogs.com/cnblogs_com/QLeelulu/201108/201108282116297285.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;这个除了查看错误信息、打印调试信息（console.log()）、写一些测试脚本以外，还可以当作Javascript API查看用。&lt;br /&gt;例如我想查看console都有哪些方法和属性，我可以直接在Console中输入"console"并执行：&lt;/p&gt;&lt;p&gt;&lt;img src="http://images.cnblogs.com/cnblogs_com/QLeelulu/201108/201108282116388520.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;怎么样，一目了然了吧 ？再例如我想查看日期函数都有哪些方法：&lt;/p&gt;&lt;p&gt;&lt;img src="http://images.cnblogs.com/cnblogs_com/QLeelulu/201108/201108282116419094.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;（&lt;span style="color: #008000;"&gt;注：注意在这里看到的某些方法和属性是ES5新增的，记得兼容其他浏览器的支持情况哦&lt;/span&gt;）&lt;/p&gt;&lt;p&gt;结语&lt;/p&gt;&lt;p&gt;Google Chrome除了简洁、快速，现在的Chrome的插件也非常的丰富了。而对于web开发者来说，Chrome对于HTML5、CSS3等一些新标准的支持也是比较完善的，而且Chrome的开发者工具我个人认为真的非常好用，这就是为什么我向web开发者推荐使用Chrome的原因。&lt;/p&gt;&lt;p&gt;注1：本文截图的Chrome版本为：13.0.782.215 m&lt;br /&gt;注2：Chrome开发者工具更详细的说明请参考：&lt;a href="http://code.google.com/intl/zh-CN/chrome/devtools/docs/overview.html"&gt;http://code.google.com/intl/zh-CN/chrome/devtools/docs/overview.html&lt;/a&gt;&lt;br /&gt;注3：本文原来想定的标题是：给那些因为Firebug而舍不得FireFox的朋友&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/QLeelulu/aggbug/2156402.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/QLeelulu/archive/2011/08/28/2156402.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/QLeelulu/archive/2011/08/10/2134206.html</id><title type="text">sqlalchemy在web.py中的session使用</title><summary type="text">按照sqlalchemy的文档中关于sqlalchemy的session在web应用上下文的生命周期应该是：Web Server Web Framework User-defined Controller Call-------------- -------------- ------------------------------web request -&gt; call controller -&gt; # call Session(). this establishes a new, # contextual Session. session = Session() # load so</summary><published>2011-08-10T13:24:00Z</published><updated>2011-08-10T13:24:00Z</updated><author><name>Q.Lee.lulu</name><uri>http://www.cnblogs.com/QLeelulu/</uri></author><link rel="alternate" href="http://www.cnblogs.com/QLeelulu/archive/2011/08/10/2134206.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/QLeelulu/archive/2011/08/10/2134206.html"/><content type="html">&lt;p&gt;按照sqlalchemy的文档中关于sqlalchemy的session在web应用上下文的生命周期应该是：&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;&lt;span style="color: #000000;"&gt;Web Server          Web Framework        User&lt;/span&gt;&lt;span style="color: #000000;"&gt;-&lt;/span&gt;&lt;span style="color: #000000;"&gt;defined Controller Call&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;--------------&lt;/span&gt;&lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #000000;"&gt;--------------&lt;/span&gt;&lt;span style="color: #000000;"&gt;       &lt;/span&gt;&lt;span style="color: #000000;"&gt;------------------------------&lt;/span&gt;&lt;span style="color: #000000;"&gt;&lt;br /&gt;web request    &lt;/span&gt;&lt;span style="color: #000000;"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;&lt;br /&gt;                    call controller &lt;/span&gt;&lt;span style="color: #000000;"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;   # call Session().  &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;this&lt;/span&gt;&lt;span style="color: #000000;"&gt; establishes a &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt;,&lt;br /&gt;                                         # contextual Session.&lt;br /&gt;                                         session &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; Session()&lt;br /&gt;&lt;br /&gt;                                         # load some objects, save some changes&lt;br /&gt;                                         objects &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; session.query(MyClass).all()&lt;br /&gt;&lt;br /&gt;                                         # some other code calls Session, it&lt;/span&gt;&lt;span style="color: #800000;"&gt;'&lt;/span&gt;&lt;span style="color: #800000;"&gt;s the&lt;/span&gt;&lt;span style="color: #800000;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;                                         # same contextual session &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;as&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #800000;"&gt;sess&lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #000000;"&gt;&lt;br /&gt;                                         session2 &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; Session()&lt;br /&gt;                                         session2.add(foo)&lt;br /&gt;                                         session2.commit()&lt;br /&gt;&lt;br /&gt;                                         # generate content to be returned&lt;br /&gt;                                         &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; generate_content()&lt;br /&gt;                    Session.remove() &lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;lt;-&lt;/span&gt;&lt;span style="color: #000000;"&gt;&lt;br /&gt;web response   &lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;lt;-&lt;/span&gt;&lt;/div&gt;&lt;p&gt;见：&lt;a href="http://www.sqlalchemy.org/docs/05/session.html#lifespan-of-a-contextual-session"&gt;http://www.sqlalchemy.org/docs/05/session.html#lifespan-of-a-contextual-session&lt;/a&gt;&lt;/p&gt;&lt;p&gt;不过web.py的cookbook中关于使用sqlalchemy的示例中，最后并没有释放sqlalchemy的session资源，正确的应该如下：&lt;/p&gt;&lt;span face="monospace" style="font-family: monospace;"&gt;&lt;/span&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;&lt;span style="color: #0000ff;"&gt;def&lt;/span&gt;&lt;span style="color: #000000;"&gt; load_sqla(handler):&lt;br /&gt;    web.ctx.orm &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; scoped_session(sessionmaker(bind&lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt;engine))&lt;br /&gt;    &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;try&lt;/span&gt;&lt;span style="color: #000000;"&gt;:&lt;br /&gt;        &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; handler()&lt;br /&gt;    &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;except&lt;/span&gt;&lt;span style="color: #000000;"&gt; web.HTTPError:&lt;br /&gt;       web.ctx.orm.commit()&lt;br /&gt;       &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;raise&lt;/span&gt;&lt;span style="color: #000000;"&gt;&lt;br /&gt;    &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;except&lt;/span&gt;&lt;span style="color: #000000;"&gt;:&lt;br /&gt;        web.ctx.orm.rollback()&lt;br /&gt;        &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;raise&lt;/span&gt;&lt;span style="color: #000000;"&gt;&lt;br /&gt;    &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;finally&lt;/span&gt;&lt;span style="color: #000000;"&gt;:&lt;br /&gt;        web.ctx.orm.commit()&lt;br /&gt;        &lt;/span&gt;&lt;span style="color: #008000;"&gt;#&lt;/span&gt;&lt;span style="color: #008000;"&gt; If the above alone doesn't work, uncomment &lt;/span&gt;&lt;span style="color: #008000;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;        &lt;/span&gt;&lt;span style="color: #008000;"&gt;#&lt;/span&gt;&lt;span style="color: #008000;"&gt; the following line:&lt;/span&gt;&lt;span style="color: #008000;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;        &lt;/span&gt;&lt;span style="color: #008000;"&gt;#&lt;/span&gt;&lt;span style="color: #008000;"&gt;web.ctx.orm.expunge_all() &lt;/span&gt;&lt;span style="color: #008000;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;        web.ctx.orm.close() &lt;/span&gt;&lt;span style="color: #008000;"&gt;#&lt;/span&gt;&lt;span style="color: #008000;"&gt; &amp;lt;=- 关闭session，或者用 .remove()&lt;/span&gt;&lt;/div&gt;&lt;span face="monospace" style="font-family: monospace;"&gt;&lt;/span&gt;&lt;p&gt;&lt;/p&gt;&lt;span face="monospace" style="font-family: monospace;"&gt;&lt;/span&gt;&lt;img src="http://www.cnblogs.com/QLeelulu/aggbug/2134206.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/QLeelulu/archive/2011/08/10/2134206.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/QLeelulu/archive/2011/08/05/2128577.html</id><title type="text">web.py大文件下载</title><summary type="text">需要下载大文件的时候，如果先将文件直接读入内容再返回，那肯定就很浪费内存，甚至会崩溃。所以我们需要读一些内容然后直接flush给客户端，但是web.py的文档里面却没有找到flush的方法。不过在web.py的cookbook中的How to Stream Large Files中看到可以直接yield返回内容。所以，我们可以使用yield来做flush做的事情。BUF_SIZE = 262144class download: def GET(self): file_name = 'file_name' file_path = os.path.join('file_pa</summary><published>2011-08-05T06:10:00Z</published><updated>2011-08-05T06:10:00Z</updated><author><name>Q.Lee.lulu</name><uri>http://www.cnblogs.com/QLeelulu/</uri></author><link rel="alternate" href="http://www.cnblogs.com/QLeelulu/archive/2011/08/05/2128577.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/QLeelulu/archive/2011/08/05/2128577.html"/><content type="html">&lt;p&gt;需要下载大文件的时候，如果先将文件直接读入内容再返回，那肯定就很浪费内存，甚至会崩溃。&lt;/p&gt;&lt;p&gt;所以我们需要读一些内容然后直接flush给客户端，但是web.py的文档里面却没有找到flush的方法。&lt;/p&gt;&lt;p&gt;不过在web.py的cookbook中的&lt;a href="http://webpy.org/cookbook/streaming_large_files" target="_blank"&gt;How to Stream Large Files&lt;/a&gt;中看到可以直接yield返回内容。所以，我们可以使用yield来做flush做的事情。&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;BUF_SIZE = 262144&lt;br/&gt;class download:&lt;br/&gt;    def GET(self):&lt;br/&gt;        file_name = 'file_name'&lt;br/&gt;        file_path = os.path.join('file_path', file_name)&lt;br/&gt;        f = None&lt;br/&gt;        try:&lt;br/&gt;            f = open(file_path, "rb")&lt;br/&gt;            webpy.header('Content-Type','application/octet-stream')&lt;br/&gt;            webpy.header('Content-disposition', 'attachment; filename=%s.dat' % file_name)&lt;br/&gt;            while True:&lt;br/&gt;                c = f.read(BUF_SIZE)&lt;br/&gt;                if c:&lt;br/&gt;                    yield c&lt;br/&gt;                else:&lt;br/&gt;                    break&lt;br/&gt;        except Exception, e:&lt;br/&gt;            print e&lt;br/&gt;            yield 'Error'&lt;br/&gt;        finally:&lt;br/&gt;            if f:&lt;br/&gt;                f.close()&lt;br/&gt;&lt;/div&gt;&lt;p&gt;OK！&lt;/p&gt;&lt;p&gt;完鸟！&lt;/p&gt;&lt;img src="http://www.cnblogs.com/QLeelulu/aggbug/2128577.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/QLeelulu/archive/2011/08/05/2128577.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/QLeelulu/archive/2011/07/31/2122379.html</id><title type="text">Python和Node.js支持尾递归吗？</title><summary type="text">什么是尾递归？简单来说就是最后返回的只是一个函数的调用，而不用保存多余的局部变量。看一个简单的计算阶乘的例子(Lua代码)：function fact(n) return n==0 and 1 or n * fact(n-1)end 改成尾递归的方式就是：function tail_fact(n, p) p = p or 1 if n==0 then return p end return tail_fact(n-1, n*p)end 关于尾递归的更详细说明请参考： http://en.wikipedia.org/wiki/Tail_call因为使用尾递归方式的时候，是不用保存局部变量的了，所</summary><published>2011-07-30T17:52:00Z</published><updated>2011-07-30T17:52:00Z</updated><author><name>Q.Lee.lulu</name><uri>http://www.cnblogs.com/QLeelulu/</uri></author><link rel="alternate" href="http://www.cnblogs.com/QLeelulu/archive/2011/07/31/2122379.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/QLeelulu/archive/2011/07/31/2122379.html"/><content type="html">&lt;p&gt;什么是尾递归？简单来说就是最后返回的只是一个函数的调用，而不用保存多余的局部变量。&lt;br /&gt;看一个简单的计算阶乘的例子(Lua代码)：&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;&lt;span style="color: #0000ff;"&gt;function&lt;/span&gt;&lt;span style="color: #000000;"&gt; fact(n)&lt;br /&gt;    &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; n&lt;/span&gt;&lt;span style="color: #000000;"&gt;==&lt;/span&gt;&lt;span style="color: #800080;"&gt;0&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;and&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #800080;"&gt;1&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;or&lt;/span&gt;&lt;span style="color: #000000;"&gt; n &lt;/span&gt;&lt;span style="color: #000000;"&gt;*&lt;/span&gt;&lt;span style="color: #000000;"&gt; fact(n&lt;/span&gt;&lt;span style="color: #000000;"&gt;-&lt;/span&gt;&lt;span style="color: #800080;"&gt;1&lt;/span&gt;&lt;span style="color: #000000;"&gt;)&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;end&lt;/span&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;改成尾递归的方式就是：&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;&lt;span style="color: #0000ff;"&gt;function&lt;/span&gt;&lt;span style="color: #000000;"&gt; tail_fact(n, p)&lt;br /&gt;    p &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; p &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;or&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #800080;"&gt;1&lt;/span&gt;&lt;span style="color: #000000;"&gt;&lt;br /&gt;    &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;if&lt;/span&gt;&lt;span style="color: #000000;"&gt; n&lt;/span&gt;&lt;span style="color: #000000;"&gt;==&lt;/span&gt;&lt;span style="color: #800080;"&gt;0&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;then&lt;/span&gt;&lt;span style="color: #000000;"&gt;&lt;br /&gt;        &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; p&lt;br /&gt;    &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;end&lt;/span&gt;&lt;span style="color: #000000;"&gt;&lt;br /&gt;    &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; tail_fact(n&lt;/span&gt;&lt;span style="color: #000000;"&gt;-&lt;/span&gt;&lt;span style="color: #800080;"&gt;1&lt;/span&gt;&lt;span style="color: #000000;"&gt;, n&lt;/span&gt;&lt;span style="color: #000000;"&gt;*&lt;/span&gt;&lt;span style="color: #000000;"&gt;p)&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;end&lt;/span&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;关于尾递归的更详细说明请参考： &lt;br /&gt;&lt;a title="http://en.wikipedia.org/wiki/Tail_call" href="http://en.wikipedia.org/wiki/Tail_call"&gt;http://en.wikipedia.org/wiki/Tail_call&lt;/a&gt;&lt;/p&gt;&lt;p&gt;因为使用尾递归方式的时候，是不用保存局部变量的了，所以部分语言的解析器会对尾递归做优化，减少栈空间的占用。普通的递归方式则由于需要保存局部变量，栈空间则越占越多，最终导致栈溢出。&lt;/p&gt;&lt;p&gt;Lua是支持尾递归的，所以上面的尾递归的代码，是可以很好的工作的。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Python的尾递归支持&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Python本身是不支持尾递归的(&lt;a href="http://stackoverflow.com/questions/33923/what-is-tail-recursion" target="_blank"&gt;via&lt;/a&gt;)，并且对递归次数有限制的，当递归次数超过1000次的时候，就会抛出&amp;ldquo;RuntimeError: maximum recursion depth exceeded&amp;rdquo;异常。&lt;br /&gt;有人对此为Python的尾递归写了一个优化版本，让Python突破递归调用1000次的限制：&lt;a href="http://code.activestate.com/recipes/474088/" target="_blank"&gt;Tail Call Optimization Decorator (Python recipe)&lt;/a&gt; ，或者你可以看看以下两篇文章：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.cnblogs.com/Alexander-Lee/archive/2010/09/16/1827587.html" target="_blank"&gt;一个很Cool的Idear-&amp;gt;Python的尾递归优化&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.codecho.com/tail-recursion/" target="_blank"&gt;尾递归(Tail Recursion)&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;以上的Python尾递归优化可以突破1000次的递归限制，但是却对于尾递归应有的优化完全没有。以下为我的测试代码：&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;&lt;span style="color: #008000;"&gt;#&lt;/span&gt;&lt;span style="color: #008000;"&gt;recursion.py&lt;/span&gt;&lt;span style="color: #008000;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;@tail_call_optimized&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;def&lt;/span&gt;&lt;span style="color: #000000;"&gt; fact(n):&lt;br /&gt;    &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #000000;"&gt;1&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;if&lt;/span&gt;&lt;span style="color: #000000;"&gt; n&lt;/span&gt;&lt;span style="color: #000000;"&gt;==&lt;/span&gt;&lt;span style="color: #000000;"&gt;0 &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;else&lt;/span&gt;&lt;span style="color: #000000;"&gt; n &lt;/span&gt;&lt;span style="color: #000000;"&gt;*&lt;/span&gt;&lt;span style="color: #000000;"&gt; fact(n&lt;/span&gt;&lt;span style="color: #000000;"&gt;-&lt;/span&gt;&lt;span style="color: #000000;"&gt;1&lt;/span&gt;&lt;span style="color: #000000;"&gt;)&lt;/span&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;&lt;span style="color: #008000;"&gt;#&lt;/span&gt;&lt;span style="color: #008000;"&gt;tail_recursion.py&lt;/span&gt;&lt;span style="color: #008000;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;@tail_call_optimized&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;def&lt;/span&gt;&lt;span style="color: #000000;"&gt; tail_fact(n, p&lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt;1&lt;/span&gt;&lt;span style="color: #000000;"&gt;):&lt;br /&gt;    &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;if&lt;/span&gt;&lt;span style="color: #000000;"&gt; n&lt;/span&gt;&lt;span style="color: #000000;"&gt;==&lt;/span&gt;&lt;span style="color: #000000;"&gt;0:&lt;br /&gt;        &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; p&lt;br /&gt;    &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; tail_fact(n&lt;/span&gt;&lt;span style="color: #000000;"&gt;-&lt;/span&gt;&lt;span style="color: #000000;"&gt;1&lt;/span&gt;&lt;span style="color: #000000;"&gt;, n&lt;/span&gt;&lt;span style="color: #000000;"&gt;*&lt;/span&gt;&lt;span style="color: #000000;"&gt;p)&lt;/span&gt;&lt;/div&gt;&lt;p&gt;测试环境是&lt;strong&gt;Python2.7.1，&lt;/strong&gt;计算100000的阶乘。执行recursion.py的时候，内存占用约为&lt;strong&gt;100M&lt;/strong&gt;，执行tail_recursion.py的时候，内存占用占到&lt;strong&gt;1G&lt;/strong&gt;的时候，还是没有执行完，我只好杀掉进程。&lt;/p&gt;&lt;p&gt;不过我确实想不明白为什么Python这里写成尾递归的方式会比会比普通方式占用多那么多内存呢？&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Node.js对尾递归的支持&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;我知道JavaScript是不支持尾递归的。ES4的时候曾经提过要加入尾递归的支持，不过后来被去掉了(&lt;a href="http://lambda-the-ultimate.org/node/3047" target="_blank"&gt;via&lt;/a&gt;)。&lt;br /&gt;周爱民的《Javascript语言精髓与编程实践》其中也提到：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&amp;ldquo;然而不幸的是。目前已知的javascript 的解释环境中并不支持这种特性（尾递归）。因此，我们在这里讨论函数室式时，可以说&amp;ldquo;能够通过函数递归来消灭循环语句&amp;rdquo;，但在不支持尾递归（及其优化技术）的javascript中，这种实现将以大量栈和内存消耗为代价&amp;rdquo;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Node.js是基于Google V8的，所以在Chrome的控制台测试了一下：&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/QLeelulu/201107/201107310151391732.png"&gt;&lt;img title="image" style="display: inline; border: 0px;" height="242" alt="image" src="http://images.cnblogs.com/cnblogs_com/QLeelulu/201107/201107310151449285.png" width="347" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;从结果看来，基本没戏了。但是还是在node.js写了代码验证一下。&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;&lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt; recursion.js&lt;/span&gt;&lt;span style="color: #008000;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;function&lt;/span&gt;&lt;span style="color: #000000;"&gt; fact(n){&lt;br /&gt;    &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;if&lt;/span&gt;&lt;span style="color: #000000;"&gt;(n &lt;/span&gt;&lt;span style="color: #000000;"&gt;==&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #000000;"&gt;0&lt;/span&gt;&lt;span style="color: #000000;"&gt;){&lt;br /&gt;        console.log(&lt;/span&gt;&lt;span style="color: #000000;"&gt;'&lt;/span&gt;&lt;span style="color: #000000;"&gt;fact: &lt;/span&gt;&lt;span style="color: #000000;"&gt;'&lt;/span&gt;&lt;span style="color: #000000;"&gt;);&lt;br /&gt;        console.dir(process.memoryUsage() );&lt;br /&gt;    }&lt;br /&gt;    &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; n&lt;/span&gt;&lt;span style="color: #000000;"&gt;==&lt;/span&gt;&lt;span style="color: #000000;"&gt;0&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #000000;"&gt;?&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #000000;"&gt;1&lt;/span&gt;&lt;span style="color: #000000;"&gt; : n &lt;/span&gt;&lt;span style="color: #000000;"&gt;*&lt;/span&gt;&lt;span style="color: #000000;"&gt; fact(n&lt;/span&gt;&lt;span style="color: #000000;"&gt;-&lt;/span&gt;&lt;span style="color: #000000;"&gt;1&lt;/span&gt;&lt;span style="color: #000000;"&gt;);&lt;br /&gt;}&lt;/span&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;&lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt; tail_recursion.js&lt;/span&gt;&lt;span style="color: #008000;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;function&lt;/span&gt;&lt;span style="color: #000000;"&gt; tailFact(n, p){&lt;br /&gt;    p &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; p &lt;/span&gt;&lt;span style="color: #000000;"&gt;||&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #000000;"&gt;1&lt;/span&gt;&lt;span style="color: #000000;"&gt;;&lt;br /&gt;    &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;if&lt;/span&gt;&lt;span style="color: #000000;"&gt;(n&lt;/span&gt;&lt;span style="color: #000000;"&gt;==&lt;/span&gt;&lt;span style="color: #000000;"&gt;0&lt;/span&gt;&lt;span style="color: #000000;"&gt;){&lt;br /&gt;        console.log(&lt;/span&gt;&lt;span style="color: #000000;"&gt;'&lt;/span&gt;&lt;span style="color: #000000;"&gt;tail fact: &lt;/span&gt;&lt;span style="color: #000000;"&gt;'&lt;/span&gt;&lt;span style="color: #000000;"&gt;);&lt;br /&gt;        console.dir(process.memoryUsage() );&lt;br /&gt;        &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; p;&lt;br /&gt;    }&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;else&lt;/span&gt;&lt;span style="color: #000000;"&gt;{&lt;br /&gt;        &lt;/span&gt;&lt;span style="color: #0000ff;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; tailFact(n&lt;/span&gt;&lt;span style="color: #000000;"&gt;-&lt;/span&gt;&lt;span style="color: #000000;"&gt;1&lt;/span&gt;&lt;span style="color: #000000;"&gt;, p&lt;/span&gt;&lt;span style="color: #000000;"&gt;*&lt;/span&gt;&lt;span style="color: #000000;"&gt;n);&lt;br /&gt;    }&lt;br /&gt;}&lt;/span&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;以下为计算13000的阶乘时内存占用情况：&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;&lt;span style="color: #000000;"&gt;$ node recursion.js &lt;br /&gt;fact: &lt;br /&gt;{ rss: &lt;/span&gt;&lt;span style="color: #000000;"&gt;7892992&lt;/span&gt;&lt;span style="color: #000000;"&gt;,&lt;br /&gt;  vsize: &lt;/span&gt;&lt;span style="color: #000000;"&gt;55169024&lt;/span&gt;&lt;span style="color: #000000;"&gt;,&lt;br /&gt;  heapTotal: &lt;/span&gt;&lt;span style="color: #000000;"&gt;2861216&lt;/span&gt;&lt;span style="color: #000000;"&gt;,&lt;br /&gt;  heapUsed: &lt;/span&gt;&lt;span style="color: #000000;"&gt;1634612&lt;/span&gt;&lt;span style="color: #000000;"&gt; }&lt;/span&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;&lt;span style="color: #000000;"&gt;$ node tail_recursion.js &lt;br /&gt;tail fact: &lt;br /&gt;{ rss: &lt;/span&gt;&lt;span style="color: #000000;"&gt;7901184&lt;/span&gt;&lt;span style="color: #000000;"&gt;,&lt;br /&gt;  vsize: &lt;/span&gt;&lt;span style="color: #000000;"&gt;55169024&lt;/span&gt;&lt;span style="color: #000000;"&gt;,&lt;br /&gt;  heapTotal: &lt;/span&gt;&lt;span style="color: #000000;"&gt;2869376&lt;/span&gt;&lt;span style="color: #000000;"&gt;,&lt;br /&gt;  heapUsed: &lt;/span&gt;&lt;span style="color: #000000;"&gt;1791520&lt;/span&gt;&lt;span style="color: #000000;"&gt; }&lt;/span&gt;&lt;/div&gt;&lt;p&gt;从结果来看，尾递归的方式占用的内存还要多。&lt;/p&gt;&lt;p&gt;下面再来看看计算13000的阶乘，循环1000次，然后计算平均每次的执行时间：&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;&lt;span style="color: #0000ff;"&gt;var&lt;/span&gt;&lt;span style="color: #000000;"&gt; start &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; Date.now();&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;for&lt;/span&gt;&lt;span style="color: #000000;"&gt;(&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;var&lt;/span&gt;&lt;span style="color: #000000;"&gt; i&lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt;0&lt;/span&gt;&lt;span style="color: #000000;"&gt;; i&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;1000&lt;/span&gt;&lt;span style="color: #000000;"&gt;; i&lt;/span&gt;&lt;span style="color: #000000;"&gt;++&lt;/span&gt;&lt;span style="color: #000000;"&gt;){&lt;br /&gt;    tailFact(&lt;/span&gt;&lt;span style="color: #000000;"&gt;13000&lt;/span&gt;&lt;span style="color: #000000;"&gt;);&lt;br /&gt;}&lt;br /&gt;console.log( (Date.now() &lt;/span&gt;&lt;span style="color: #000000;"&gt;-&lt;/span&gt;&lt;span style="color: #000000;"&gt; start)&lt;/span&gt;&lt;span style="color: #000000;"&gt;/&lt;/span&gt;&lt;span style="color: #000000;"&gt;1000 );&lt;/span&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;以下为执行结果：&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;&lt;span style="color: #000000;"&gt;$ node recursion.js &lt;br /&gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;0.257&lt;/span&gt;&lt;span style="color: #000000;"&gt;&lt;br /&gt;&lt;br /&gt;$ node tail_recursion.js &lt;br /&gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;0.277&lt;/span&gt;&lt;/div&gt;&lt;p&gt;阿门，无论是内存占用还是执行效率，尾递归的方式都要比普通方式差。&lt;/p&gt;&lt;p&gt;看来V8是对于尾递归的方式完全没有做优化了，&lt;span style="text-decoration: line-through;"&gt;对于Node.js异步调用到处是的情况下，没有对尾调用做优化的话，栈空间浪费很严重啊！不知道我这样认为对不对？&lt;/span&gt;忘记一点是&amp;ldquo;异步&amp;rdquo;的，异步回调栈是清空的了，不存在该问题。&lt;/p&gt;&lt;p&gt;Enjoy!&lt;/p&gt;&lt;img src="http://www.cnblogs.com/QLeelulu/aggbug/2122379.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/QLeelulu/archive/2011/07/31/2122379.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/QLeelulu/archive/2011/07/13/2105692.html</id><title type="text">小文件、nginx、Redis、Moosefs</title><summary type="text">现在有3KW的数据，单条数据都很小的，如果按key-value来看的话，key就是32位的MD5字符串，value按平均算大概是100字节左右。现在需要将这些数据做缓存以在高并非的时候依然可以快速响应。因为这些数据基本没有冷热数据之分，所以需要将全部数据都放到缓存中。1、直接生成静态文件，利用nginx对静态文件的高效做静态缓存。当时服务器硬件资源有限，所以就采用这种方式，一直源用至今。服务器间通过NFS来共享太多小文件，不方便管理NFS不方便运维与扩展文件内容很小(100字节左右)，3KW大概就是2.5G大小左右不过文件存储的时候和硬盘分区的族大小有关，在这里磁盘分区的族大小为8K，所以尽管</summary><published>2011-07-13T12:38:00Z</published><updated>2011-07-13T12:38:00Z</updated><author><name>Q.Lee.lulu</name><uri>http://www.cnblogs.com/QLeelulu/</uri></author><link rel="alternate" href="http://www.cnblogs.com/QLeelulu/archive/2011/07/13/2105692.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/QLeelulu/archive/2011/07/13/2105692.html"/><content type="html">&lt;p&gt;现在有3KW的数据，单条数据都很小的，如果按key-value来看的话，key就是32位的MD5字符串，value按平均算大概是100字节左右。&lt;/p&gt;&lt;p&gt;现在需要将这些数据做缓存以在高并非的时候依然可以快速响应。&lt;br /&gt;因为这些数据基本没有冷热数据之分，所以需要将全部数据都放到缓存中。&lt;/p&gt;&lt;p&gt;1、直接生成静态文件，利用nginx对静态文件的高效做静态缓存。&lt;/p&gt;&lt;ul&gt;&lt;ul&gt;&lt;li&gt;当时服务器硬件资源有限，所以就采用这种方式，一直源用至今。&lt;/li&gt;&lt;li&gt;服务器间通过NFS来共享&lt;/li&gt;&lt;li&gt;太多小文件，不方便管理&lt;/li&gt;&lt;li&gt;NFS不方便运维与扩展&lt;/li&gt;&lt;li&gt;文件内容很小(100字节左右)，3KW大概就是2.5G大小左右&lt;/li&gt;&lt;ul&gt;&lt;li&gt;不过文件存储的时候和硬盘分区的族大小有关，在这里磁盘分区的族大小为8K，所以尽管文件内容只有100字节，但是实际存储到磁盘上的时候单个文件其实是8K&lt;/li&gt;&lt;li&gt;所以3KW的文件世界占的磁盘空间大约为：200G左右（&lt;strong&gt;&lt;span color="#ff0000" style="color: #ff0000;"&gt;严重浪费空间啊&lt;/span&gt;&lt;/strong&gt;）&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;&lt;/blockquote&gt;&lt;p&gt;2、Redis(V2.2.11)【KV数据库】&lt;/p&gt;&lt;ul&gt;&lt;ul&gt;&lt;li&gt;听同事说开启VM会使性能急剧下降，所以基本无视VM，数据全放内存。&lt;/li&gt;&lt;li&gt;key为32位MD5字符串&lt;/li&gt;&lt;li&gt;测试数据：10W数据大概占内存20M&lt;/li&gt;&lt;li&gt;测试数据：500W数据大概占内存1G，持久化的rdb数据文件大概350M&lt;/li&gt;&lt;li&gt;推算3KW数据：内存6G，持久化的rdb数据文件大概为2G(压缩了？)&lt;/li&gt;&lt;li&gt;因为Redis在持久化的时候内存会加倍，和考虑到数据的增长，所以需要1台20G内存的机器基本就没问题了（容灾啥的另算）。&lt;/li&gt;&lt;li&gt;Redis非常快，如果硬件条件没问题，基本选这个最好了。&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;p&gt;3、Moosefs(MFS)【分布式文件存储系统】&lt;/p&gt;&lt;ul&gt;&lt;ul&gt;&lt;li&gt;mfs支持NFS的方式mount到本地直接操作（如使用mfs，则现在的架构基本不用改）&lt;/li&gt;&lt;li&gt;最基本的需要一台主控服务器(Master Server)、一台数据服务器(Chunk Server)&lt;/li&gt;&lt;li&gt;文件和目录的索引需要全部加载到主控服务器的内存中，所以对主控服务器的内存有一定的要求&lt;/li&gt;&lt;li&gt;写入30W文件，到20W的时候写入就开始下降得厉害了（我的5400转的笔记本硬盘）&lt;/li&gt;&lt;li&gt;30W文件，4W目录，主控服务器占用大概120M内存&lt;/li&gt;&lt;li&gt;文件存储方式貌似和普遍的文件一样单个存储的（不确定），30W文件大概占了2.4G的磁盘空间（同样是8K一个文件）。&lt;/li&gt;&lt;li&gt;小文件一样很多，不方便维护与迁移(不知是否我设置不对？)。&lt;/li&gt;&lt;li&gt;内存、硬盘都占用得比较多，而且性能相对来说不是很出众。&lt;/li&gt;&lt;li&gt;所以这个基本不考虑了。&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;img src="http://www.cnblogs.com/QLeelulu/aggbug/2105692.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/QLeelulu/archive/2011/07/13/2105692.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/QLeelulu/archive/2011/06/13/2079965.html</id><title type="text">一道JavaScript面试题（setTimeout）</title><summary type="text">下面的代码，多久之后会弹出'end'？ 为什么？var t = true;setTimeout(function(){ t = false; }, 1000);while(t){ }alert('end');这是以前在想有没办法实现阻塞javascript线程的时候（即实现sleep方法），想过的一种实现。很简单，是吧？是吗？</summary><published>2011-06-13T10:13:00Z</published><updated>2011-06-13T10:13:00Z</updated><author><name>Q.Lee.lulu</name><uri>http://www.cnblogs.com/QLeelulu/</uri></author><link rel="alternate" href="http://www.cnblogs.com/QLeelulu/archive/2011/06/13/2079965.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/QLeelulu/archive/2011/06/13/2079965.html"/><content type="html">&lt;p&gt;下面的代码，多久之后会弹出'end'？ 为什么？&lt;/p&gt;&lt;p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;var t = true;&lt;br/&gt;&lt;br/&gt;setTimeout(function(){ t = false; }, 1000);&lt;br/&gt;&lt;br/&gt;while(t){ }&lt;br/&gt;&lt;br/&gt;alert('end');&lt;br/&gt;&lt;/div&gt;&lt;/p&gt;&lt;p&gt;这是以前在想有没办法实现阻塞javascript线程的时候（即实现sleep方法），想过的一种实现。&lt;/p&gt;&lt;p&gt;很简单，是吧？&lt;/p&gt;&lt;p&gt;是吗？&lt;/p&gt;&lt;img src="http://www.cnblogs.com/QLeelulu/aggbug/2079965.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/QLeelulu/archive/2011/06/13/2079965.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/QLeelulu/archive/2011/05/06/2039266.html</id><title type="text">用Eclipse调试Node.js代码</title><summary type="text">node.js是基于Google V8的，而Google V8有一个Eclipse的调试插件，这个插件同样也支持node.js。1、安装Eclipse debugger for V8这个，用过Eclipse的应该都知道，不过还是简单说下吧： 选择“Install New Software” 点“Add” Location为： http://chromedevtools.googlecode.com/svn/update/dev/Name你喜欢，整一个方便你记忆的就好。 点击确定后，在“Work with“选择你刚才添加的站点： 然后选择“Chromium JavaScript Remote D</summary><published>2011-05-06T10:56:00Z</published><updated>2011-05-06T10:56:00Z</updated><author><name>Q.Lee.lulu</name><uri>http://www.cnblogs.com/QLeelulu/</uri></author><link rel="alternate" href="http://www.cnblogs.com/QLeelulu/archive/2011/05/06/2039266.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/QLeelulu/archive/2011/05/06/2039266.html"/><content type="html">&lt;p&gt;node.js是基于Google V8的，而Google &lt;a target="_blank" href="http://code.google.com/p/chromedevtools/"&gt;V8有一个Eclipse的调试插件&lt;/a&gt;，这个插件同样也支持node.js。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;1、安装Eclipse debugger for V8&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;这个，用过Eclipse的应该都知道，不过还是简单说下吧：&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/QLeelulu/201105/201105061855259060.png"&gt;&lt;img height="308" width="312" src="http://images.cnblogs.com/cnblogs_com/QLeelulu/201105/201105061855253138.png" alt="wps_clip_image-13545" border="0" title="wps_clip_image-13545" style="display: inline; border: 0px;" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;选择&amp;ldquo;Install New Software&amp;rdquo; &lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/QLeelulu/201105/201105061855264500.png"&gt;&lt;img height="271" width="609" src="http://images.cnblogs.com/cnblogs_com/QLeelulu/201105/201105061855269451.png" alt="wps_clip_image-13957" border="0" title="wps_clip_image-13957" style="display: inline; border: 0px;" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;点&amp;ldquo;Add&amp;rdquo; &lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/QLeelulu/201105/201105061855273322.png"&gt;&lt;img height="123" width="630" src="http://images.cnblogs.com/cnblogs_com/QLeelulu/201105/201105061855272416.png" alt="wps_clip_image-14038" border="0" title="wps_clip_image-14038" style="display: inline; border: 0px;" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;Location为： &lt;a href="http://chromedevtools.googlecode.com/svn/update/dev/"&gt;http://chromedevtools.googlecode.com/svn/update/dev/&lt;/a&gt;&lt;br /&gt;Name你喜欢，整一个方便你记忆的就好。 &lt;/p&gt;&lt;p&gt;点击确定后，在&amp;ldquo;Work with&amp;ldquo;选择你刚才添加的站点：&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/QLeelulu/201105/201105061855275415.png"&gt;&lt;img height="161" width="326" src="http://images.cnblogs.com/cnblogs_com/QLeelulu/201105/201105061855289286.png" alt="wps_clip_image-14557" border="0" title="wps_clip_image-14557" style="display: inline; border: 0px;" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;然后选择&amp;ldquo;Chromium JavaScript Remote Debugger&amp;rdquo;，然后一直下一步，安装完后会提示重启Eclipse，重启Eclipse后就可以开始调试了。 &lt;/p&gt;&lt;p&gt;&lt;strong&gt;2、怎样调试Nodejs？ &lt;/strong&gt;&lt;/p&gt;&lt;p&gt;从插件名称中的&amp;ldquo;Remote&amp;rdquo;可以预想到这是一个远程调试的工具，大概的流程就是node开一个tcp的调试端口，然后这个调试工具通过这个tcp端口来和node通讯实现调试。 &lt;/p&gt;&lt;p&gt;要启用node的调试端口，在执行node脚本的时候需要添加 &lt;span style="background-color: #ff9900;"&gt;&amp;ndash;-debug&lt;/span&gt; 参数： &lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;&lt;div&gt;&lt;span style="color: #000000;"&gt;node &lt;/span&gt;&lt;span style="color: #000000;"&gt;--&lt;/span&gt;&lt;span style="color: #000000;"&gt;debug[&lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt;port] NodeApp.js&lt;br /&gt;&lt;br /&gt;or&lt;br /&gt;&lt;br /&gt;node &lt;/span&gt;&lt;span style="color: #000000;"&gt;--&lt;/span&gt;&lt;span style="color: #000000;"&gt;debug&lt;/span&gt;&lt;span style="color: #000000;"&gt;-&lt;/span&gt;&lt;span style="color: #000000;"&gt;brk[&lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt;port] NodeApp.js&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;其中port为开启的调试端口，默认为5858.&lt;br /&gt;--debug和--debug-brk的区别在于，--debug执行脚本的时候会直接运行该脚本，而--debug-brk执行脚本的时候，并不会马上执行，而是等待调试器的连接，然后按调试器的指令来执行。 &lt;/p&gt;&lt;p&gt;我们写个简单的代码来用于调试： &lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/QLeelulu/201105/201105061855288696.png"&gt;&lt;img height="173" width="500" src="http://images.cnblogs.com/cnblogs_com/QLeelulu/201105/201105061855293331.png" alt="wps_clip_image-17441" border="0" title="wps_clip_image-17441" style="display: inline; border: 0px;" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;然后用 &lt;span style="background-color: #ffff99;"&gt;node &amp;ndash;debug hello_world.js&lt;/span&gt; 来运行： &lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/QLeelulu/201105/201105061855293614.png"&gt;&lt;img height="77" width="405" src="http://images.cnblogs.com/cnblogs_com/QLeelulu/201105/201105061855299121.png" alt="wps_clip_image-17588" border="0" title="wps_clip_image-17588" style="display: inline; border: 0px;" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;可以看到输出一行：debugger listening on port 5858&lt;br /&gt;5858为默认端口，你也可以用 &lt;span style="background-color: #ff9900;"&gt;--debug=5859&lt;/span&gt; 来指定不同的端口 &lt;/p&gt;&lt;p&gt;好，现在node的调试模式已经运行起来了，我们去配置Eclipse来连接到node并进行调试。 &lt;/p&gt;&lt;p&gt;首先我们要到debug config里面去添加一个新的V8 VM的调试配置： &lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/QLeelulu/201105/201105061855304562.png"&gt;&lt;img height="515" width="339" src="http://images.cnblogs.com/cnblogs_com/QLeelulu/201105/201105061855317004.png" alt="wps_clip_image-18682" border="0" title="wps_clip_image-18682" style="display: inline; border: 0px;" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;右键，选择&amp;ldquo;new&amp;rdquo;来新建一个配置项：&lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/QLeelulu/201105/201105061855329903.png"&gt;&lt;img height="501" width="581" src="http://images.cnblogs.com/cnblogs_com/QLeelulu/201105/201105061855338201.png" alt="wps_clip_image-18917" border="0" title="wps_clip_image-18917" style="display: inline; border: 0px;" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;因为我们刚才node起的调试端口为默认的5858，所以这里我们的端口就是5858，名称我们定为&amp;ldquo;Node-5858&amp;rdquo;。 &lt;/p&gt;&lt;p&gt;然后点debug开始调试，或者你使用下面的方式开始调试： &lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/QLeelulu/201105/201105061855339804.png"&gt;&lt;img height="75" width="255" src="http://images.cnblogs.com/cnblogs_com/QLeelulu/201105/201105061855336183.png" alt="wps_clip_image-20213" border="0" title="wps_clip_image-20213" style="display: inline; border: 0px;" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;调试模式大概会是这样： &lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/QLeelulu/201105/20110506185535478.png"&gt;&lt;img height="594" width="783" src="http://images.cnblogs.com/cnblogs_com/QLeelulu/201105/20110506185536379.png" alt="wps_clip_image-20478" border="0" title="wps_clip_image-20478" style="display: inline; border: 0px;" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;（注：这是调试视图，点击右上角的臭虫按钮。如果你的Eclipse上没有这个按钮，请点击上图右上角臭虫左边的添加按钮，找到debug然后添加就可以） &lt;/p&gt;&lt;p&gt;在调试模式连接成功后，你会在你的&amp;ldquo;Project Explorer&amp;rdquo;里面看到多了一个&amp;ldquo;Node-5858&amp;rdquo;（刚才debug config里面设置的名称）的项目，里面的文件都是调试的文件或者调试的文件require进来的文件。&lt;br /&gt;打开这些文件，你就可以在里面加断点开始调试了。例如上图的第8行加了一个断点，则每次在浏览器访问的时候都会进入这个断点。 &lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/QLeelulu/201105/201105061855375297.png"&gt;&lt;img height="557" width="332" src="http://images.cnblogs.com/cnblogs_com/QLeelulu/201105/201105061855373835.png" alt="wps_clip_image-21004" border="0" title="wps_clip_image-21004" style="display: inline; border: 0px;" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;其他的调试和你平时用Eclipse调试其他代码是一样的。&lt;br /&gt;Eclipse的调试快捷键是，F5单步进入，F6单步跳过。 &lt;/p&gt;&lt;p&gt;最后说一下 --debug-brk 方式启动的调试模式： &lt;/p&gt;&lt;p&gt;&lt;a href="http://images.cnblogs.com/cnblogs_com/QLeelulu/201105/201105061855371850.png"&gt;&lt;img height="67" width="355" src="http://images.cnblogs.com/cnblogs_com/QLeelulu/201105/201105061855383769.png" alt="wps_clip_image-22682" border="0" title="wps_clip_image-22682" style="display: inline; border: 0px;" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;可以看到仅仅是输出了一行&amp;ldquo;debugger listening on port 5858&amp;rdquo;而已，后面&lt;span style="background-color: #ff9900;"&gt;并没有&lt;/span&gt;继续输出&amp;ldquo;Server running at &amp;hellip;..&amp;rdquo;。&lt;br /&gt;这是因为用 启动的调试模式并不会马上执行代码，而是会等待调试器的连接（可以理解为在hello_world.js的第一行加了断点），具体还是各位童鞋自己实践吧。 &lt;/p&gt;&lt;p&gt;参考： &lt;a href="https://github.com/joyent/node/wiki/Using-Eclipse-as-Node-Applications-Debugger"&gt;https://github.com/joyent/node/wiki/Using-Eclipse-as-Node-Applications-Debugger&lt;/a&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/QLeelulu/aggbug/2039266.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/QLeelulu/archive/2011/05/06/2039266.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry></feed>
