<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>江淼的Blog</title>
	<atom:link href="http://www.jiangmiao.org/blog/feed" rel="self" type="application/rss+xml" />
	<link>http://www.jiangmiao.org/blog</link>
	<description>简单生活</description>
	<lastBuildDate>Sat, 24 Dec 2011 07:02:44 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.4</generator>
		<item>
		<title>Linux下的数据统计</title>
		<link>http://www.jiangmiao.org/blog/2542.html</link>
		<comments>http://www.jiangmiao.org/blog/2542.html#comments</comments>
		<pubDate>Fri, 23 Dec 2011 14:26:10 +0000</pubDate>
		<dc:creator>JiangMiao</dc:creator>
				<category><![CDATA[Linux]]></category>

		<guid isPermaLink="false">http://www.jiangmiao.org/blog/?p=2542</guid>
		<description><![CDATA[最近2天CSDN的密码泄漏，部份人可能会像我一样去作一些统计，比如邮箱占有率等一些数据。统计方式五花八门，但我觉得在Linux下用命令组合统计最为方便。 一、基本统计 先看密码文档 www.csdn.net.sql 格式用户名 # 密码 # 邮箱以&#8217; # &#8216;分列3个字符可以用awk等进行切割 使用到的相关统计命令与参数为 sort -g 按照 常规数值排序 -r 逆序输出排序结果 -k 排序的列 uniq -c 统计数量 -d 只输出重复的行 注: uniq只能对sort过的数据统计 例：统计密码使用频率并按使用频率从多到少排列awk -F &#8216; # &#8216; &#8216;{print $2}&#8217; www.csdn.net.sql&#124;sort&#124;uniq -cd&#124;sort -rgk1&#124;tee password_frequency.txt输出 235012 123456789 &#8230; <a href="http://www.jiangmiao.org/blog/2542.html">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>最近2天CSDN的密码泄漏，部份人可能会像我一样去作一些统计，比如邮箱占有率等一些数据。统计方式五花八门，但我觉得在Linux下用命令组合统计最为方便。<br />
<h3>一、基本统计</h3>
<p>先看密码文档 www.csdn.net.sql 格式<br />用户名 # 密码 # 邮箱<br />以&#8217; # &#8216;分列<br />3个字符可以用awk等进行切割</p>
<p>使用到的相关统计命令与参数为
<div class="pre">
<pre>
sort
  -g 按照 常规数值排序
  -r  逆序输出排序结果
  -k 排序的列

uniq
  -c 统计数量
  -d 只输出重复的行
</pre>
</div>
<p>注: uniq只能对sort过的数据统计</p>
<p>例：统计密码使用频率并按使用频率从多到少排列<br />awk -F &#8216; # &#8216; &#8216;{print $2}&#8217; www.csdn.net.sql|sort|uniq -cd|sort -rgk1|tee password_frequency.txt<br />输出
<div class="pre">
<pre>
 235012 123456789
 212749 12345678
  76346 11111111
  46053 dearbook
  34952 00000000

...
</pre>
</div>
<p>例2：统计邮箱域名使用频率<br />@之后的都作为域名一部份，并转成小写，转成小写也可以通过命令tr [:upper:] [:lower:]<br />perl -pe &#8216;s/.*@(.*)/lc($1)/ei&#8217; www.csdn.net.sql|tr -d &#8220;\r&#8221;|sort|uniq -c|sort -rgk1 > email_frequency.txt
<div class="pre">
<pre>
1976210 qq.com
1766931 163.com
 807897 126.com
 351594 sina.com
 205491 yahoo.com.cn
...
</pre>
</div>
<p>例3：统计邮箱提供商频率<br />比如vip.qq.com和qq.com都作qq，只统计常用域名com, net, edu等<br />perl -ne &#8216;/.*@.*?([^\.]+)\.(com|edu|net|org|cn).*/i &#038;&#038; print &#8220;\L$1\n&#8221;&#8216; www.csdn.net.sql|sort|uniq -c|sort -rgk1 > email_agency_frequency.txt
<div class="pre">
<pre>
2012384 qq
1785057 163
 808173 126
 396855 sina
 326406 yahoo
 204509 hotmail
 187087 gmail
 105379 sohu
  72470 tom
...
</pre>
</div>
<h3>二、图形化统计结果</h3>
<p>图形化的工具有gnuplot，R语言等，我这里使用了R语言</p>
<p>例4：由邮箱频率前9名与其余总和生成饼图<br />输出前9名与其总和 awk &#8216;NR < 10 { print $1, $2 } NR >= 10 { others += $1} END { print others, &#8220;others&#8221; }&#8217; email_agency_frequency.txt > email_agency_top10.txt
<div class="pre">
<pre>
2012384 qq
1785057 163
808173 126
396855 sina
326406 yahoo
204509 hotmail
187087 gmail
105379 sohu
72470 tom
516409 others
</pre>
</div>
<p>用R语言输出饼图<br />R脚本
<div class="pre">
<pre>
table &lt;- read.table(&quot;email_agency_top10.txt&quot;)
percent &lt;- round(table$V1/sum(table$V1)*100)
png(file=&quot;email_agency_market_share.png&quot;, width=500, height=500)
pie(table$V1, labels=paste(table$V2, &#039;(&#039;, percent, &#039;%)&#039;, sep=&quot;&quot;), col=rainbow(length(table$V1)), main=&quot;邮箱占有率&quot;, family=&#039;DejaVu Sans&#039;)
</pre>
</div>
<p><img src="http://www.jiangmiao.org/blog/wp-content/uploads/2011/12/email_agency_market_share.png" alt="" title="email_agency_market_share" width="500" height="500" class="alignnone size-full wp-image-2547" /><br />
<h3>三、相关链接</h3>
<p><a href="http://www.gnu.org/software/gawk/manual/" target="_blank">gawk</a><br /><a href="http://www.grymoire.com/Unix/Sed.html" target="_blank">sed</a><br /><a href="http://www.perl.org/docs.html" target="_blank">perl</a><br /><a href="http://www.r-project.org/" target="_blank">R语言</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.jiangmiao.org/blog/2542.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>node.js成也异步，败也异步，评node.js的异步特性</title>
		<link>http://www.jiangmiao.org/blog/2491.html</link>
		<comments>http://www.jiangmiao.org/blog/2491.html#comments</comments>
		<pubDate>Mon, 31 Oct 2011 19:02:48 +0000</pubDate>
		<dc:creator>JiangMiao</dc:creator>
				<category><![CDATA[javascript]]></category>
		<category><![CDATA[编程]]></category>

		<guid isPermaLink="false">http://www.jiangmiao.org/blog/?p=2491</guid>
		<description><![CDATA[node.js最大的卖点就是异步，声称以此获得更高的性能，而我认为，node之所以快并不是因为异步而快，而是因为V8而快。异步仅在资源占有明显优势，而引入异步却大大增加了编程的复杂度，且异步在http服务上并没有或者无法用在刀刃上。 以目前node来看，其作为单独http服务器的实现远远不如nginx，若以node建站，更普遍的选择是nginx 反向代理 node，一则由于node作为http服务器功能简单，实现更是差nginx几个台阶，其次因node单线程特性，若要发挥多核的优势，也必然会开2个以上的node进程，由此nginx + node几乎是首选模式，如果使用cluster，可以达到不错的性能，但也是因为简单而快，非异步的优势。相对于nginx + n * php-cgi模式，其工作模式近似看成 nginx + n*65535*node，n*65535*node为假想的大量worker，n为node进程数。 首先看传统的 nginx + 50*php-cgi 工作模式。如果使用php-fpm进行fastcgi spawn，那么平每个空php-fpm基础占用物理内存6.4M，50个php-cgi则占用了 320M + 每个请求占用的内存。而nginx + 4*node，占用的内存仅为 52M + 每个请求占用的内存 。 同样100个worker会有100个不同的持久化连接，而node可以通过各种connections pool，使其共享持久化连接，大大减少其总连接数，node可以在任意时刻把一个连接取出或放回连接池而几乎没有性能上的损失。 这也是node异步资源上的优势。而除此之外，异步并没有想像中的这么美。 一、 异步在http服务器上表现 1. 充分利用等待时间的谎言 先看完整一次http请求，花费的时间可能是 40ms 服务器从客户端连接并接收数据5ms 各类数据传输与接收2ms 数据处理1ms &#8230; <a href="http://www.jiangmiao.org/blog/2491.html">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>node.js最大的卖点就是异步，声称以此获得更高的性能，而我认为，node之所以快并不是因为异步而快，而是因为V8而快。异步仅在资源占有明显优势，而引入异步却大大增加了编程的复杂度，且异步在http服务上并没有或者无法用在刀刃上。</p>
<p>以目前node来看，其作为单独http服务器的实现远远不如nginx，若以node建站，更普遍的选择是nginx 反向代理 node，一则由于node作为http服务器功能简单，实现更是差nginx几个台阶，其次因node单线程特性，若要发挥多核的优势，也必然会开2个以上的node进程，由此nginx + node几乎是首选模式，如果使用cluster，可以达到不错的性能，但也是因为简单而快，非异步的优势。相对于nginx + n * php-cgi模式，其工作模式近似看成 nginx + n*65535*node，n*65535*node为假想的大量worker，n为node进程数。</p>
<p>首先看传统的 nginx + 50*php-cgi 工作模式。<br />如果使用php-fpm进行fastcgi spawn，那么平每个空php-fpm基础占用物理内存6.4M，50个php-cgi则占用了 320M + 每个请求占用的内存。<br />而nginx + 4*node，占用的内存仅为 52M + 每个请求占用的内存 。</p>
<p>同样100个worker会有100个不同的持久化连接，而node可以通过各种connections pool，使其共享持久化连接，大大减少其总连接数，node可以在任意时刻把一个连接取出或放回连接池而几乎没有性能上的损失。</p>
<p>这也是node异步资源上的优势。而除此之外，异步并没有想像中的这么美。<br />
<h3>一、 异步在http服务器上表现</h3>
<h4>1.  充分利用等待时间的谎言</h4>
<p>先看完整一次http请求，花费的时间可能是 <br />40ms 服务器从客户端连接并接收数据<br />5ms 各类数据传输与接收<br />2ms 数据处理<br />1ms rendering<br />10ms 服务器向客户端发送数据</p>
<p>由此可以近似看成 55ms等待时间 + 3ms 数据实际处理时间。<br />但由于nginx fastcgi buffer，upload等的存在，对于php-cgi实际等待时间仅为 5ms，如果数据库处理的很糟糕，等待时间则延长为 50ms，由于存在50个worker，那么相当于每个worker延长了1ms，所以node的充分利用等待时间本身就形成了一个伪命题。由于1ms的等待那么php-cgi将占用的cpu最大为75%，等待中的25%，正好可以给系统其它进程所利用，似乎也物尽其用。且若是CPU真得持续跑在50%以上了，那也到了不得不升级硬件的时候了。<br />
<h4>2.  无法出众的http性能</h4>
<p>node作为独立服务器，可以达到不俗的性能，而由若与nginx配合，对比nginx + php-cgi中并没有占到太多优势。在不同机器上快约-10%~25%不等，差距并不明显。若是完整用例的快，是因为V8的出色表现，和异步与否并没有太大的关系。<br />
<h4>3.  艰难的异步之路</h4>
<p>并不是说异步难写，而是相对于同步来讲，如今有各种异步实现模型，其跟本的目的也是简化异步实现。而异步再简化，再优雅都还是异步，易用性比起同步来讲仍然是天地之别。用繁复的异步换取不多的性能提升，实在是得不尝失。<br />
<h3>二、 node异步的用武之地</h3>
<p>批判了node的异步，但异步也并非一无是处，worker无法很好胜任的场合是异步的舞台。</p>
<p>各种需要要持久化连接的非http连接的服务器，如网游服务器。</p>
<p>大量远程api调用，假设每次请求都会有2~3次通过服务器的远程api调用，那么每个请求会有400ms以上的等待时间。而这类请求数量过多，会导致阻塞了普通动态页面请求。需要增大的worker数量，或者使用不同通道的worker。但显然没有异步来得实惠，而且这类请求逻辑通常不会复杂。</p>
<p>简言之，如果传统的线程池或者多进程worker，数量不得不达到100以上，那么就是异步的用武之地了。<br />
<h3>三、 一组hello world的测试</h3>
<p>在四核 AMD Phenom 9650 下的一组最简单的hello world的测试结果<br />nginx + node sock
<div class="pre">
<pre>
var http   = require(&#039;http&#039;);
http.createServer(function (req, res) {
  res.writeHead(200, {&#039;Content-Type&#039;: &#039;text/plain&#039;});
  res.end(&#039;Hello World\n&#039;);
}).listen(&quot;/tmp/node-&quot;+process.argv[2]+&quot;.sock&quot;);
</pre>
</div>
<p>node + cluster
<div class="pre">
<pre>
var http    = require(&#039;http&#039;);
var cluster = require(&#039;cluster&#039;)
var server  = http.createServer(function (req, res) {
  res.writeHead(200, {&#039;Content-Type&#039;: &#039;text/plain&#039;});
  res.end(&#039;Hello World\n&#039;);
});
cluster(server).listen(1337);
</pre>
</div>
<p>及php
<div class="pre">
<pre>
&lt;?php
echo &#039;hello world&#039;;
</pre>
</div>
<p>测试结果如下，单位(rps)<br />20并发与100并发<br />
<table>
<tr>
<td width="33.33%"></td>
<td width="33.33%">siege -c 20</td>
<td width="33.33%">ab -c 100</td>
</tr>
<tr>
<td width="33.33%">node + cluster </td>
<td width="33.33%"> 12548 </td>
<td width="33.33%"> 19194 </td>
</tr>
<tr>
<td width="33.33%">nginx + 5*node sock </td>
<td width="33.33%">  7260</td>
<td width="33.33%"> 12803</td>
</tr>
<tr>
<td width="33.33%">nginx + php-fpm </td>
<td width="33.33%">  8400  </td>
<td width="33.33%">11242</td>
</tr>
</table>
<p>无并发<br />
<table>
<tr>
<td width="33.33%"></td>
<td width="33.33%">siege -c 1</td>
<td width="33.33%">ab -c 1</td>
</tr>
<tr>
<td width="33.33%">node + cluster </td>
<td width="33.33%"> 6019 </td>
<td width="33.33%"> 6535 </td>
</tr>
<tr>
<td width="33.33%">nginx + 5*node sock </td>
<td width="33.33%">  3024</td>
<td width="33.33%"> 3830</td>
</tr>
<tr>
<td width="33.33%">nginx + php-fpm </td>
<td width="33.33%">  3839  </td>
<td width="33.33%">4297</td>
</tr>
</table>
<p>从测试结果可以发现，node + cluster 最快，nginx + php-fpm 次之，而nginx + node sock最慢。<br />也意味着 php-fpm 甚至快于 node sock，而cluster因其功能简单，node又没有php般完整http请求初始化，综合评价，node的底层实现不出众，异步优势更是无法得到充份的体现，</p>
<p>有人会说，hello world没用到异步，只是对入口的测试，对于单连接，同步在性能上并不会弱于异步，异步的优势只能在大规模持久连接或大延迟中才能得到体现。正如我上文充分利用等待时间的谎言所述，我对node与php下PostgreSQL查询性能比较，两者性能是几乎一致的。而php下memcache的实现就很不如意，比起异步还是同步更多取决于语言本身，不过这些不在本文讨论范围之内。本文主要讨论node的异步在http服务下情况，而非node vs php或者v8 vs php，<br />
<h3>四、 小结</h3>
<p>本文不否认node快，但快与异步与否并没有太大关系，只因node简单，更重要的是其背后的v8引擎。对于逻辑复杂的网站，抛开异步是更佳的选择。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jiangmiao.org/blog/2491.html/feed</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>node.js异步数据库连接，事务查询思考</title>
		<link>http://www.jiangmiao.org/blog/2478.html</link>
		<comments>http://www.jiangmiao.org/blog/2478.html#comments</comments>
		<pubDate>Sun, 30 Oct 2011 09:00:14 +0000</pubDate>
		<dc:creator>JiangMiao</dc:creator>
				<category><![CDATA[javascript]]></category>
		<category><![CDATA[编程]]></category>

		<guid isPermaLink="false">http://www.jiangmiao.org/blog/?p=2478</guid>
		<description><![CDATA[首先思考一下场景 1、同时有50个并发请求，2、每个请求将连接PgSQL并执行一个事务： 调用2个不同的Model Bill与Profile，执行 Bill.insert 与 Profile.update3、PgSQL最大连接数为20 因为使用到事务，所以同一个数据库连接不可能同用于两个不同的http请求 如果在PHP中，那么开20个不同的php-cgi，并对每个php-cgi进行操作，其余30个在请求nginx队列1、nginx接受50个http请求2、php-cgi接受20个请求，并建立20个全局持久化连接 db3、Model Bill 与 Profile 通过全局变量 db 进行操作4、cgi结束进行各种资源，连接回收5、对队列中下一个请求进行操作 在node中行为将变成1、接受50个http请求2、从最大连接数为20的连接池中取得一个连接局域变量db，其余30个连接请求加入队列3、Model Bill 与 Profile 通过某种途径访问局域变量进行操作4、单个请求完毕，对资源连接回收5、对队列中下一个请求进行操作 由此，对比PHP与node，本质上的不同仅仅是 db 变量的全局与局域的区别， 一、解决方法 以下测试均在CPU Atom D510 1.66G 单核下测试。 1. 通过vm 通过vm的runInNewContext可以把局域变量变成全局变量，但性能上大打折扣， 对于空脚本的 script.runInNewContext() 为 1386 tps，script.runInThisContext() 为 416667 &#8230; <a href="http://www.jiangmiao.org/blog/2478.html">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>首先思考一下场景</p>
<p>1、同时有50个并发请求，<br />2、每个请求将连接PgSQL并执行一个事务： 调用2个不同的Model Bill与Profile，执行 Bill.insert 与 Profile.update<br />3、PgSQL最大连接数为20</p>
<p>因为使用到事务，所以同一个数据库连接不可能同用于两个不同的http请求</p>
<p>如果在PHP中，那么开20个不同的php-cgi，并对每个php-cgi进行操作，其余30个在请求nginx队列<br />1、nginx接受50个http请求<br />2、php-cgi接受20个请求，并建立20个全局持久化连接 db<br />3、Model Bill 与 Profile 通过全局变量 db 进行操作<br />4、cgi结束进行各种资源，连接回收<br />5、对队列中下一个请求进行操作</p>
<p>在node中行为将变成<br />1、接受50个http请求<br />2、从最大连接数为20的连接池中取得一个连接局域变量db，其余30个连接请求加入队列<br />3、Model Bill 与 Profile 通过某种途径访问局域变量进行操作<br />4、单个请求完毕，对资源连接回收<br />5、对队列中下一个请求进行操作</p>
<p>由此，对比PHP与node，本质上的不同仅仅是 db 变量的全局与局域的区别，<br />
<h3>一、解决方法</h3>
<p>以下测试均在CPU Atom D510 1.66G 单核下测试。<br />
<h4>1. 通过vm</h4>
<p>通过vm的runInNewContext可以把局域变量变成全局变量，但性能上大打折扣， 对于空脚本的 <br />script.runInNewContext() 为 1386 tps，<br />script.runInThisContext() 为 416667 tps<br />eval 为 13966 tps，<br />空循环 为 Infinity tps</p>
<p>由上述可列公式，<br />在runInNewContext中的最终性能为 1386x / (1386 + x)<br />在runInThisContext中的最终性能为  416667x / (416667 + x)</p>
<p>比如，原程序通过使用node达到了1000 rps，也是node使用http.createServer跑hello world的性能<br />重新设计并使用scriptInNewContext后，那么性能最佳也只能有 1386k / 2386 =  580 rps，<br />而在实际使用中，包含一次redis查询的完整应用，包含render，cache等部份可以达到 550 rps，那么runInNewContext性能降至 316 rps，<br />而相对应的php，包含一次redis查询的更复杂的完整应用，也可以保持在240 rps，对比，使用了scriptInNewContext后，node不再具有性能优势。</p>
<p>如果使用scriptInThisContext，性能只下降到  416667k / 417667 = 997 rps，几乎没有影响。但在这里没啥用。scriptInThisContext用于模版rendering是非常之不错。<br />
<h4>2. 通过建立model后赋于变量</h4>
<p>每个Model实例添加额外的变量，用以保存当前请求将要用到的连接。<br />那么 model 则由new Model(arg1, arg2, &#8230;) 变成 req.create(Model, arg1, arg2, &#8230;)，似乎能很好的解决创建问题。<br />但若要执行静态函数，Model.find_or_create 等， 变成 req.exec(Model, Model.find_or_create, arg1, arg2, &#8230;.)，感觉上就不漂亮了。<br />
<h4>3. Model模版</h4>
<p>使用闭包生成一个新的Model类，是个好方法，在Model的使用上也无区别。对性能的影响为 714k tps， 如果每次必须重新生成10个Model， 则为71k，对性能的影响也是微乎其微。<br />ModelTemplate模型 ToffeeScript 代码
<div class="pre">
<pre>
ModelTemplate = (req) -&gt;
  {db} = req
  class Model
    @create: -&gt;
      console.info &quot;create #{db}&quot;

st = Date.now()
for i in [1..1000]
  Model = ModelTemplate({db: &#039;hello&#039;})

console.info Date.now() - st
</pre>
</div>
<p>如果有多个Model<br />比如 class Bill, class Profile，改进成
<div class="pre">
<pre>
ModelTemplate = (req) -&gt;
  {db} = req
  class Bill
    @create: -&gt;
      console.info &quot;create bill #{db}&quot;

  class Profile
    @create: -&gt;
      console.info &quot;create profile #{db}&quot;

  {Bill, Profile}

st = Date.now()
for i in [1..1e4]
  models = ModelTemplate({db: :hello})
  {Bill} = models

console.info 1e4 * 1e3 / (Date.now() - st)
</pre>
</div>
<p>但仍然有个缺点，各个Model揉在一起，再改进成
<div class="pre">
<pre>

ModelTemplateBill = (req) -&gt;
  {db} = req
  class Bill
    @create: -&gt;
      console.info &quot;create bill #{db}&quot;

ModelTemplateProfile = (req) -&gt;
  class Profile
    @create: -&gt;
      console.info &quot;create profile #{db}&quot;

ModelTemplate = (req) -&gt;
  {db} = req

  {Bill}    = ModelTemplateBill(req)
  {Profile} = ModelTemplateProfile(req)

  {Bill, Profile}

st = Date.now()
for i in [1..1e4]
  models = ModelTemplate({db: :hello})
  {Bill} = models

console.info 1e4 * 1e3 / (Date.now() - st)
</pre>
</div>
<p>若再借用exports思想，那么可以变成
<div class="pre">
<pre>
# models/bill.toffee
ModelTemplateBill = (req) -&gt;
  {db} = req
  class Bill
    @create: -&gt;
      console.info &quot;create bill #{db}&quot;

module.exports = ModelTemplateBill

#----
ModelTemplate = (req) -&gt;
  @BillTemplate    ?= require(&#039;./models/bill&#039;)
  @ProfileTemplate ?= require(&#039;./models/profile&#039;)

  Bill    = @BillTemplate(req)
  Profile = @ProfileTemplate(req)

  {Bill, Profile}

st = Date.now()
for i in [1..1e4]
  models = ModelTemplate({db: :hello})
  {Bill} = models

console.info 1e4 * 1e3 / (Date.now() - st)
</pre>
</div>
<h4>4. 资源池</h4>
<p>由于Model的引入的最主要目的是对连接的控制，达到类似连接池的效果，因此由此脱离req，建立持久化连接池才是根本目的<br />代码则变成
<div class="pre">
<pre>
class ResourcePool
  # 代码略

st = Date.now()
res_pool = ResourcePool.create({db: :hello})

for i in [1..1e4]
  res = res_pool.create()
  {Bill, db} = res
  res.close()

console.info 1e4 * 1e3 / (Date.now() - st)
</pre>
</div>
<p>而resurce中的各个连接池独立，且redis，pgsql最大连接数量可以不同，只要在设计成在执行查询时进行连接即可，只要保证在resource中的db等连接在一次生命周期永远是同一指向即可。<br />
<h3>二、小结</h3>
<p>资源池应该是最佳方案，性能，易用性兼得。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jiangmiao.org/blog/2478.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>ToffeeScript &#8211; 支持异步语法的CoffeeScript</title>
		<link>http://www.jiangmiao.org/blog/2462.html</link>
		<comments>http://www.jiangmiao.org/blog/2462.html#comments</comments>
		<pubDate>Thu, 20 Oct 2011 17:31:02 +0000</pubDate>
		<dc:creator>JiangMiao</dc:creator>
				<category><![CDATA[javascript]]></category>
		<category><![CDATA[编程]]></category>

		<guid isPermaLink="false">http://www.jiangmiao.org/blog/?p=2462</guid>
		<description><![CDATA[ToffeeScript是CoffeeScript衍生，在完全兼容CoffeeScript的语法下提供了一些新的特性。 一、 特性一览 异步语法支持 Ruby Symbol语法的字串 正则运算符 =~ 正则Magic标识符 \&#038; \~ \1..9 1. 异步语法支持 语法: 在调用的函数尾加上!(感叹号)输入: do -&#62; # ! always is a function foo_0_0! @va = obj.foo_2_1! &#039;pa&#039;, &#039;pb&#039; # @ is inherited [va, @vb] = obj::foo_2_2! &#039;pa&#039;, &#039;pb&#039; &#8230; <a href="http://www.jiangmiao.org/blog/2462.html">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>ToffeeScript是CoffeeScript衍生，在完全兼容CoffeeScript的语法下提供了一些新的特性。<br />
<h3>一、 特性一览</h3>
<ol>
<li>异步语法支持</li>
<li>Ruby Symbol语法的字串</li>
<li>正则运算符 =~</li>
<li>正则Magic标识符 \&#038; \~ \1..9</li>
</ol>
<h4>1.  异步语法支持</h4>
<p>语法: 在调用的函数尾加上!(感叹号)<br />输入:
<div class="pre">
<pre>
    do -&gt;
      # ! always is a function
      foo_0_0!
      @va = obj.foo_2_1! &#039;pa&#039;, &#039;pb&#039;
      # @ is inherited
      [va, @vb] = obj::foo_2_2! &#039;pa&#039;, &#039;pb&#039;

    # another async block
    do -&gt;
      @va = @foo! &#039;pa&#039;

    # if, while and so on has block too
    if true
      va = foo!
    else
      vb = foo!
</pre>
</div>
<p>输出:
<div class="pre">
<pre>
    var _this = this;

    (function() {
      var _this = this;
      return foo_0_0(function() {
        return obj.foo_2_1(&#039;pa&#039;, &#039;pb&#039;, function(va) {
          _this.va = va;
          return obj.prototype.foo_2_2(&#039;pa&#039;, &#039;pb&#039;, function(va, vb) {
            _this.vb = vb;
          });
        });
      });
    })();

    (function() {
      var _this = this;
      return this.foo(&#039;pa&#039;, function(va) {
        _this.va = va;
      });
    })();

    if (true) {
      foo(function(va) {});
    } else {
      foo(function(vb) {});
    }
</pre>
</div>
<h5>a.  原理</h5>
<p>ToffeeScript 会把
<div class="pre">
<pre>
    [any expression] = foo!(params)
    other expression
</pre>
</div>
<p>转换为
<div class="pre">
<pre>
    foo params, (any expression) =&gt;
      other expression
</pre>
</div>
<p>因此
<div class="pre">
<pre>
    [a = &#039;3&#039;, @b = &#039;4&#039;] = foo!
    @a = foo!
    ...
    等等
</pre>
</div>
<p>都是有效的异步语法<br />
<h4>2.  Symbol语法的字串</h4>
<p>ToffeeScript引用了Ruby Symbol的语法，但本质仍是字串，可以看成一种字串的便捷写法。<br />语法: 以:开头的字串 /^\:((?:\\.|\w|-)+)/<br />备注: &#8211; 是有效的字串部份，<br />输入:
<div class="pre">
<pre>
    :hello_world
    :hello-world
</pre>
</div>
<p>输出:
<div class="pre">
<pre>
    &#039;hello_world&#039;
    &#039;hello-world&#039;
</pre>
</div>
<h4>3.  正则运算符 =~</h4>
<p>语法: 字串 =~ 正则表达式<br />输入:
<div class="pre">
<pre>
    &quot;hello&quot; =~ /\w+/
</pre>
</div>
<p>输出:
<div class="pre">
<pre>
    var __matches = null;
    __matches = &quot;hello&quot;.match(/\w+/);
</pre>
</div>
<h4>4.  正则Magic标识符 \&#038; \~ \1..9</h4>
<p>Magic标识符:
<div class="pre">
<pre>
    \~: the match
    \&amp;: match[0]
    \1: match[1]
    \2: match[2]
    ...
    \9: match[9]
</pre>
</div>
<p>输入:
<div class="pre">
<pre>
    if :hello =~ /^\w+$/
      console.info :matched

    if :333-444 =~ /^(\d+)-(\d+)$/
      console.info \1, \2
</pre>
</div>
<p>输出:
<div class="pre">
<pre>
    (function() {
      var __matches = null;
      if (__matches = &#039;hello&#039;.match(/^\w+$/)) console.info(&#039;matched&#039;);
      if (__matches = &#039;333-444&#039;.match(/^(\d+)-(\d+)$/)) {
        console.info(__matches[1], __matches[2]);
      }
    }).call(this);
</pre>
</div>
<h3>二、 安装</h3>
<div class="pre">
<pre>
npm install -g toffee-script
</pre>
</div>
<p>ToffeeScript有两个可执行文件 <b>toffee</b> and <b>tcons</b> 相对于CoffeeScript的 coffee 与 cake<br />
<h3>三、 相关链接</h3>
<p><a href="https://github.com/jiangmiao/toffee-script" target="_blank">ToffeeScript Github</a><br /><a href="https://github.com/jashkenas/coffee-script" target="_blank">CoffeeScript Github</a><br /><a href="http://jashkenas.github.com/coffee-script/" target="_blank">COffeeScript 语法介绍</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.jiangmiao.org/blog/2462.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Dart试用手记 – 2、语法与评论</title>
		<link>http://www.jiangmiao.org/blog/2407.html</link>
		<comments>http://www.jiangmiao.org/blog/2407.html#comments</comments>
		<pubDate>Tue, 11 Oct 2011 04:38:51 +0000</pubDate>
		<dc:creator>JiangMiao</dc:creator>
				<category><![CDATA[编程]]></category>

		<guid isPermaLink="false">http://www.jiangmiao.org/blog/?p=2407</guid>
		<description><![CDATA[Dart的语法比较传统，可以看到Java，C++的影子 1. 注释 // 单行注释/* &#8230; */ 注释块 2. 变量 Dart有2种变量var与finalfinal必需要初使化且只能赋值一次 3. 函数 Dart的函数格式：[返回类型] [函数名] 参数列表 函数体参数列表与函数体是必需的其余可省略而 Dart的函数体有2种形式=> 单一表达式{ 各种表达式 } 由此以函数都是合法的 (a, b) =&#62; a + b; () =&#62; &#039;yes&#039;; (a, b) { return a + b; }; () &#8230; <a href="http://www.jiangmiao.org/blog/2407.html">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Dart的语法比较传统，可以看到Java，C++的影子<br />
<h4>1.  注释</h4>
<p>// 单行注释<br />/* &#8230; */  注释块<br />
<h4>2. 变量</h4>
<p>Dart有2种变量var与final<br />final必需要初使化且只能赋值一次<br />
<h4>3. 函数</h4>
<p>Dart的函数格式：[返回类型] [函数名] 参数列表 函数体<br />参数列表与函数体是必需的其余可省略<br />而 Dart的函数体有2种形式<br />=> 单一表达式<br />{ 各种表达式 }</p>
<p>由此以函数都是合法的
<div class="pre">
<pre>
(a, b) =&gt; a + b;
() =&gt; &#039;yes&#039;;
(a, b) { return a + b; };
() { return &#039;yes&#039;; };
add(a, b) =&gt; a+b;
int add2(a, b) { return a+b; };
</pre>
</div>
<p>匿名函数使用的小例子
<div class="pre">
<pre>
print((a, b) { return a + b; }(3, 4)); // 输出 7
print(((a, b) =&gt; a + b)(3,4)); // 输出 7
</pre>
</div>
<p>同时函数可以写成<br />final add = (a, b) => a + b;<br />但只能在函数体中使用，无法在类与全局中使用，否则会出 Error: line 1 pos 13: initializer must be a compile time constant 错误<br />合法
<div class="pre">
<pre>
main()
{
	final add = (a, b) =&gt; a + b; //合法
	print(add(3,4));
}
</pre>
</div>
<p>不合法
<div class="pre">
<pre>
class Foo
{
	final add = (a, b) =&gt; a + b; // 不合法 1
}
final add = (a, b) =&gt; a + b; // 不合法 2，1与2两者实质是一样的

main ()
{
}
</pre>
</div>
<h4>4. 闭包</h4>
<p>Dart可谓是为专门闭包而生，由以上的函数定义，可以写一个闭包的小例子
<div class="pre">
<pre>
foo()
{
	var hello = &#039;hello&#039;;
	return () {
		return hello;
	};
}
main()
{
	print(foo()()); // 输出 hello
}
</pre>
</div>
<h4>5. 类</h4>
<p>Dart万物皆类，所以类是Dart中不可缺少的一部分<br />类定义
<div class="pre">
<pre>
class 类名称 { [各种成员与方法] }
</pre>
</div>
<p>方法定义
<div class="pre">
<pre>
[static] [返回类型] [get|set] 名称 参数列表
</pre>
</div>
<p>抽象方法
<div class="pre">
<pre>
abstract [static] [返回类型] [get|set] 名称
</pre>
</div>
<p>由以上类定义写一个类的小例子
<div class="pre">
<pre>
class Foo
{
	static add(a, b) =&gt; a + b;
	sub(a, b)
	{
		return a - b;
	}

	get a()
	{
		return &#039;a&#039;;
	}

} 

main()
{
	print(Foo.add(3, 4));         // 输出 7
	print((new Foo()).sub(4, 3)); // 输出 1
	print((new Foo()).a); // Getter a，输出 a
}
</pre>
</div>
<p>类继承，Dart只支持单继承<br />class 类名 extends 类名<br />调用父方法 super</p>
<p>Dart支持多个接口<br />interface, implements 与 factory<br />interface 名称 [factory 名称]<br />{<br />}</p>
<p>class 名称 [implements 以,分割的多个名称]<br />{<br />}<br />
<h4>6. 数组与Hash</h4>
<p>[ ] Array 例 [1, 2]<br />{} Hash 例 {&#8216;a&#8217;: &#8216;b&#8217;}<br />
<h4>7. 循环</h4>
<div class="pre">
<pre>
for (名称 in 容器) {
}

for (定义; 条件; 执行) {
}

while (条件) {
}

do {
} while (条件);
</pre>
</div>
<p>例
<div class="pre">
<pre>
main()
{
	for (var i in [1, 2]) {
		print(i);
	}

	for (var i=0; i&lt;10; ++i) {
		print(i);
	}

	var i =0;
	while (i &lt; 10) {
		print(i);
		++i;
	}

	i = 0;
	do {
		print(i);
		++i;
	} while (i &lt; 10);

}
</pre>
</div>
<h2>静观其变</h2>
<p>==在试验中发现如下代码==
<div class="pre">
<pre>
main()
{
	var st = new Date.now();
	var j = 0;
	for (var i=1; i &lt;= 100000; ++i)
	{
		j += i;
	}
	var ed = new Date.now();

	print(j);
	print(ed.difference(st));
}
</pre>
</div>
<p>输出
<div class="pre">
<pre>
5000050000
0:00:00.288
</pre>
</div>
<p>288ms，对比ruby的73ms，V8的5ms，C的2ms可谓相当之慢，使用命令为out/Release_ia32/dart_bin hello.dart，希望是我使用上的问题。且Dart的语法略显拙劣，由此我放弃继续对Dart的学习，静观其变。<br />
<h2>Dart评论</h2>
<p>缺点与疑点<br />1、class {} 后不能接分号<br />理论上;号作为分隔符存在class {};理应是合法的，class行为过于诡异。</p>
<p>2、Dart强制分号作分割<br />说不上好坏，但定位显得有问题，对于部份不习惯用;结尾的js使用者来说会有不适</p>
<p>3、怪异的私有变量声明，前置 _<br />根据Dart规范中描述前置 _ 变量名意为私有，_在C里是作为系统或内部命令存在，而在Dart中成了普遍，更奇怪的除了若要声明私有除了前置_别无选择。</p>
<p>4、展开的&#8217;字串行为<br />对于目前所有流行语言，皆为&#8221;#{嵌入的语句}&#8221;或&#8221;{$foo}&#8221;等，而单引号不展开，而Dart中单引号却会展开如 &#8216;hello $world&#8217;</p>
<p>5、不尽人意的性能<br />Dart的纯面向对象的设定出发点是支持的，我也希望能有好的表现，但现在来看此设定大大影响了语言的性能，而且实现上似乎有问题，在数值计算中连Ruby都比不过，Dart若用于Canvas，游戏运算等，定会面对大量的数值运算，如果未来性能仍然不佳，难免沦落成为一个鸡肋的存在。</p>
<p>优点<br />更加完整的OO支持，OO虽然不是必需的，但有比没有好，但担心复杂的特性或多或少会带来性能上的损失，不清楚Dart能优化到什么程度。</p>
<p>同样Dart的严格，使灵活性大大不如Javascript，失去灵活性代码量必然会上升，严格与灵活，各有所长，但在追求代码简练高产的脚本领域，Dart显得有些劣势。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jiangmiao.org/blog/2407.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Dart试用手记 – 1、编译与安装</title>
		<link>http://www.jiangmiao.org/blog/2393.html</link>
		<comments>http://www.jiangmiao.org/blog/2393.html#comments</comments>
		<pubDate>Mon, 10 Oct 2011 17:49:51 +0000</pubDate>
		<dc:creator>JiangMiao</dc:creator>
				<category><![CDATA[编程]]></category>

		<guid isPermaLink="false">http://www.jiangmiao.org/blog/?p=2393</guid>
		<description><![CDATA[今天Google发布了Dart，定位用以替代JavaScript，从架势来看未来应该也会有所投入，加之Google在V8的丰富经验，Dart定能有出色的发挥，所以打算第一时间了解下。但Dart究竟如何，是否有足够的竞争力，还要待使用后才能有定论。 一、安装 1. 准备 Linux系统，chromium提供了一个安装依赖的脚本 $ wget http://src.chromium.org/svn/trunk/src/build/install-build-deps.sh $ source install-build-deps.sh 不过我跳过了这步，不知效果如何，install-build-deps会自动检测系统环境并使用相应的包管理工具进行安装包 2. 安装Depot_tools Dart使用的是用depot_tools管理代码，可从chromium上checkout depot_tools svn co http://src.chromium.org/svn/trunk/tools/depot_tools 3. 配置gclient Dart有两种不同的包all与standalone，all包含eclipse之类的软件，功能全体积大，而standalone仅仅是dart，体积小，30M左右 gclient config http://dart.googlecode.com/svn/trunk/deps/standalone.deps 4. 同步代码 depot_tools/gclient sync 5. 修改一个gcc的小问题 因dart在我使用的gcc 4.6.1会出../runtime/vm/parser.cc:3666:12: 警告：variable ‘expr_pos’ set but not used [-Wunused-but-set-variable]加上-Werror导至编译失败。处理方法：修改tools/gyp/configurations_mak.gypi第13行注释掉#&#8217;-Werror&#8217;再使用 &#8230; <a href="http://www.jiangmiao.org/blog/2393.html">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>今天Google发布了Dart，定位用以替代JavaScript，从架势来看未来应该也会有所投入，加之Google在V8的丰富经验，Dart定能有出色的发挥，所以打算第一时间了解下。但Dart究竟如何，是否有足够的竞争力，还要待使用后才能有定论。<br />
<h3>一、安装</h3>
<h4>1. 准备</h4>
<p>Linux系统，chromium提供了一个安装依赖的脚本
<div class="pre">
<pre>
$ wget http://src.chromium.org/svn/trunk/src/build/install-build-deps.sh
$ source install-build-deps.sh
</pre>
</div>
<p>不过我跳过了这步，不知效果如何，install-build-deps会自动检测系统环境并使用相应的包管理工具进行安装包<br />
<h4>2. 安装Depot_tools</h4>
<p>Dart使用的是用depot_tools管理代码，可从chromium上checkout depot_tools
<div class="pre">
<pre>
svn co http://src.chromium.org/svn/trunk/tools/depot_tools
</pre>
</div>
<h4>3. 配置gclient</h4>
<p>Dart有两种不同的包all与standalone，all包含eclipse之类的软件，功能全体积大，而standalone仅仅是dart，体积小，30M左右
<div class="pre">
<pre>
gclient config http://dart.googlecode.com/svn/trunk/deps/standalone.deps
</pre>
</div>
<h4>4. 同步代码</h4>
<div class="pre">
<pre>
depot_tools/gclient sync
</pre>
</div>
<h4>5. 修改一个gcc的小问题</h4>
<p>因dart在我使用的gcc 4.6.1会出<br />../runtime/vm/parser.cc:3666:12: 警告：variable ‘expr_pos’ set but not used [-Wunused-but-set-variable]<br />加上-Werror导至编译失败。<br />处理方法：修改tools/gyp/configurations_mak.gypi第13行注释掉#&#8217;-Werror&#8217;<br />再使用 depot_tools/gclient runhooks 重新生成Makefile等文件<br />
<h4>6. 编译</h4>
<p>我直接生成debug与release两个版本
<div class="pre">
<pre>
cd dart
../tools/build.py --arch=ia32 --mode=all
</pre>
</div>
<p>如果是64位则用&#8211;arch=x64 ../tools/build.py &#8211;help查看更多帮助。<br />生成的文件在out/Release_ia32与out/Debug_ia32中<br />有不少文件，我比较关心的有以下5个<br />dart 需要动态链接库的可执行文件<br />dart_bin 无需动态链接库的可执行文件<br />lib.target/libdart.so 动态链接库<br />另外有2个无snapshot版的<br />dart_no_snapshot 与 dart_no_snapshot_bin<br />无snapshot同V8一样，体积小但初始运行速行慢<br />
<h4>7. 测试</h4>
<p>测试用的参数可以使用编译时参数一致进行全面测试
<div class="pre">
<pre>
../tools/test.py --arch=ia32 --mode=all
# 也可以仅测试其中的部份，如
../tools/test.py --arch=ia32 --mode=release
</pre>
</div>
<h3>二、介绍</h3>
<p>在下载和编译时过一遍语法和特性，全部规范只有78页，不知是语言简单还是文档简单。<br /><a href="http://www.dartlang.org/docs/spec/index.html" target="_blank">Dart规范下载页</a><br />
<h4>1. Dart的基本特性</h4>
<p>Dart是基于类，单继承，纯面向对象语言。<br />Dart程序可以做一些静态检查<br />Dart可以以2种方式运行，产品模式与检查模式<br />Dart只能单线程运行，若要并行可以通过isolates，每一个isolate有自已的内存与线程。<br />
<h3>三、Hello World</h3>
<div class="pre">
<pre>
main() {
  print(&#039;Hello World&#039;);
}
</pre>
</div>
<h3>四、相关链接</h3>
<p><a href="http://www.dartlang.org/" target="_blank">Dart官网</a><br /><a href="https://code.google.com/p/dart/" target="_blank">Dart源码</a><br /><a href="http://www.dartlang.org/docs/api/index.html" target="_blank">Dart库参考</a><br /><a href="http://www.dartlang.org/docs/spec/dartLangSpec.pdf" target="_blank">Dart规范PDF</a><br /><a href="http://code.google.com/p/gclient/" target="_blank">gclient主页</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.jiangmiao.org/blog/2393.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>CoffeeScript 功能加强</title>
		<link>http://www.jiangmiao.org/blog/2299.html</link>
		<comments>http://www.jiangmiao.org/blog/2299.html#comments</comments>
		<pubDate>Thu, 01 Sep 2011 18:42:54 +0000</pubDate>
		<dc:creator>JiangMiao</dc:creator>
				<category><![CDATA[javascript]]></category>

		<guid isPermaLink="false">http://www.jiangmiao.org/blog/?p=2299</guid>
		<description><![CDATA[CoffeScript makes javascript fun, and the CoffeeScript&#8217;s source code write clearly and easy to extend, I add 2 string related features: Ruby symbol like string and long string. CoffeeScript让javascript变得有趣，而且代码清晰，易用扩展，我在CoffeeScript的原基础上加入2个新字符串相关的语法。一个是类似Ruby Symbol的字串，一个是超长字串 1. Ruby Symbol like CoffeeScript: console.info :hello, :world JavaScript: console.info(&#039;hello&#039;, &#8230; <a href="http://www.jiangmiao.org/blog/2299.html">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>CoffeScript makes javascript fun, and the CoffeeScript&#8217;s source code write clearly and easy to extend, I add 2 string related features: Ruby symbol like string and long string.</p>
<p>CoffeeScript让javascript变得有趣，而且代码清晰，易用扩展，我在CoffeeScript的原基础上加入2个新字符串相关的语法。一个是类似Ruby Symbol的字串，一个是超长字串<br />
<h4>1. Ruby Symbol like</h4>
<p><span style="color:blue">CoffeeScript:</span>
<div class="pre">
<pre>
console.info :hello, :world
</pre>
</div>
<p>JavaScript:
<div class="pre">
<pre>
console.info(&#039;hello&#039;, &#039;world&#039;);
</pre>
</div>
<p>Remark:
<div class="pre">
<pre>
What will be translated to for those code?
1. info:hello
{info: hello}

2. {:hello, :world}
ERROR! use {hello, world} instead
</pre>
</div>
<h4>2.  正则表达示运算符</h4>
<div class="pre">
<pre>
if :hello =~ /^\w+$/
  console.info :ok, \&amp;
</pre>
</div>
<p>生成
<div class="pre">
<pre>
var __matches = null;
if (__matches = &#039;hello&#039;.match(/^\w+$/))
  console.info(&#039;ok&#039;, __matches[0]);
</pre>
</div>
<h4>3. Links</h4>
<p><a href="https://github.com/jiangmiao/coffee-script" target="_blank">My forked CoffeeScript GitHub Repo with those 2 features</a><br /><a href="https://github.com/jashkenas/coffee-script" target="_blank">Original CoffeeScript GitHub Repo</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.jiangmiao.org/blog/2299.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Linux libaio</title>
		<link>http://www.jiangmiao.org/blog/2290.html</link>
		<comments>http://www.jiangmiao.org/blog/2290.html#comments</comments>
		<pubDate>Thu, 18 Aug 2011 07:51:08 +0000</pubDate>
		<dc:creator>JiangMiao</dc:creator>
				<category><![CDATA[C/C++]]></category>
		<category><![CDATA[编程]]></category>

		<guid isPermaLink="false">http://www.jiangmiao.org/blog/?p=2290</guid>
		<description><![CDATA[Linux aio是Linux下的异步读写模型。对于文件的读写，即使以O_NONBLOCK方式来打开一个文件，也会处于&#8221;阻塞&#8221;状态。因为文件时时刻刻处于可读状态。而从磁盘到内存所等待的时间是惊人的。为了充份发挥把数据从磁盘复制到内存的时间，引入了aio模型。linux下有aio封装，但是aio采用的是线程或信号用以通知，为了能更多的控制io行为，可以使用更为低级libaio。 一、基本函数与结构 1. libaio函数 extern int io_setup(int maxevents, io_context_t *ctxp); extern int io_destroy(io_context_t ctx); extern int io_submit(io_context_t ctx, long nr, struct iocb *ios[]); extern int io_cancel(io_context_t ctx, struct iocb *iocb, struct io_event *evt); extern int io_getevents(io_context_t ctx_id, long min_nr, &#8230; <a href="http://www.jiangmiao.org/blog/2290.html">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Linux aio是Linux下的异步读写模型。<br />对于文件的读写，即使以O_NONBLOCK方式来打开一个文件，也会处于&#8221;阻塞&#8221;状态。因为文件时时刻刻处于可读状态。而从磁盘到内存所等待的时间是惊人的。为了充份发挥把数据从磁盘复制到内存的时间，引入了aio模型。linux下有aio封装，但是aio采用的是线程或信号用以通知，为了能更多的控制io行为，可以使用更为低级libaio。<br />
<h3>一、基本函数与结构</h3>
<h4>1. libaio函数</h4>
<div class="pre">
<pre>
extern int io_setup(int maxevents, io_context_t *ctxp);
extern int io_destroy(io_context_t ctx);
extern int io_submit(io_context_t ctx, long nr, struct iocb *ios[]);
extern int io_cancel(io_context_t ctx, struct iocb *iocb, struct io_event *evt);
extern int io_getevents(io_context_t ctx_id, long min_nr, long nr, struct io_event *events, struct timespec *timeout);
</pre>
</div>
<h4>2. 结构</h4>
<div class="pre">
<pre>
struct io_iocb_poll {
	PADDED(int events, __pad1);
};	/* result code is the set of result flags or -&#039;ve errno */

struct io_iocb_sockaddr {
	struct sockaddr *addr;
	int		len;
};	/* result code is the length of the sockaddr, or -&#039;ve errno */

struct io_iocb_common {
	PADDEDptr(void	*buf, __pad1);
	PADDEDul(nbytes, __pad2);
	long long	offset;
	long long	__pad3;
	unsigned	flags;
	unsigned	resfd;
};	/* result code is the amount read or -&#039;ve errno */

struct io_iocb_vector {
	const struct iovec	*vec;
	int			nr;
	long long		offset;
};	/* result code is the amount read or -&#039;ve errno */

struct iocb {
	PADDEDptr(void *data, __pad1);	/* Return in the io completion event */
	PADDED(unsigned key, __pad2);	/* For use in identifying io requests */

	short		aio_lio_opcode;
	short		aio_reqprio;
	int		aio_fildes;

	union {
		struct io_iocb_common		c;
		struct io_iocb_vector		v;
		struct io_iocb_poll		poll;
		struct io_iocb_sockaddr	saddr;
	} u;
};

struct io_event {
	PADDEDptr(void *data, __pad1);
	PADDEDptr(struct iocb *obj,  __pad2);
	PADDEDul(res,  __pad3);
	PADDEDul(res2, __pad4);
};
</pre>
</div>
<h4>3. 内联函数</h4>
<div class="pre">
<pre>
static inline void io_set_callback(struct iocb *iocb, io_callback_t cb);
static inline void io_prep_pread(struct iocb *iocb, int fd, void *buf, size_t count, long long offset);
static inline void io_prep_pwrite(struct iocb *iocb, int fd, void *buf, size_t count, long long offset);
static inline void io_prep_preadv(struct iocb *iocb, int fd, const struct iovec *iov, int iovcnt, long long offset);
static inline void io_prep_pwritev(struct iocb *iocb, int fd, const struct iovec *iov, int iovcnt, long long offset);
/* Jeff Moyer says this was implemented in Red Hat AS2.1 and RHEL3.
 * AFAICT, it was never in mainline, and should not be used. --RR */
static inline void io_prep_poll(struct iocb *iocb, int fd, int events);
static inline int io_poll(io_context_t ctx, struct iocb *iocb, io_callback_t cb, int fd, int events);
static inline void io_prep_fsync(struct iocb *iocb, int fd);
static inline int io_fsync(io_context_t ctx, struct iocb *iocb, io_callback_t cb, int fd);
static inline void io_prep_fdsync(struct iocb *iocb, int fd);
static inline int io_fdsync(io_context_t ctx, struct iocb *iocb, io_callback_t cb, int fd);
static inline void io_set_eventfd(struct iocb *iocb, int eventfd);
</pre>
</div>
<h3>二、使用方法</h3>
<p>1、初使化io_context<br />2、open文件取得fd<br />3、根据fd，buffer offset等息建立iocb<br />4、submit iocb到context<br />5、io_getevents取得events状态<br />6、回到3步<br />
<h3>三、例子</h3>
<div class="pre">
<pre class="cpp" name="code">#include &lt;unistd.h&gt;
#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;
#include &lt;error.h&gt;
#include &lt;errno.h&gt;

#include &lt;fcntl.h&gt;
#include &lt;libaio.h&gt;

int main(int argc, char *argv[])
{
	// 每次读入32K字节
	const int buffer_size = 0x8000;

	// 最大事件数 32
	const int nr_events   = 32;
	int rt;

	io_context_t ctx = {0};

	// 初使化 io_context_t
	rt = io_setup(nr_events, &amp;ctx);
	if ( rt != 0 )
		error(1, rt, &quot;io_setup&quot;);

	// 依次读取参数作为文件名加入提交到ctx
	int pagesize = sysconf(_SC_PAGESIZE);
	for (int i=1; i&lt;argc; ++i) {
		iocb *cb = (iocb*)malloc(sizeof(iocb));
		void *buffer;
		// 要使用O_DIRECT, 必须要对齐
		posix_memalign(&amp;buffer, pagesize, buffer_size);
		io_prep_pread(cb, open(argv[i], O_RDONLY | O_DIRECT), buffer, buffer_size, 0);
		rt = io_submit(ctx, 1, &amp;cb);
		if (rt &lt; 0)
			error(1, -rt, &quot;io_submit %s&quot;, argv[i]);;
	}

	io_event events[nr_events];
	iocb     *cbs[nr_events];

	int remain = argc - 1;
	int n      = 0;

	// 接收数据最小返回的请求数为1，最大为nr_events
	while (remain &amp;&amp; (n = io_getevents(ctx, 1, nr_events, events, 0))) {
		int nr_cbs = 0;
		for (int i=0; i&lt;n; ++i) {
			io_event &amp;event = events[i];
			iocb     *cb    = event.obj;
			// event.res为unsigned
			//printf(&quot;%d receive %d bytes\n&quot;, cb-&gt;aio_fildes, event.res);
			if (event.res &gt; buffer_size) {
				printf(&quot;%s\n&quot;, strerror(-event.res));
			}
			if (event.res != buffer_size || event.res2 != 0) {
				--remain;
				// 释放buffer, fd 与 cb
				free(cb-&gt;u.c.buf);
				close(cb-&gt;aio_fildes);
				free(cb);
			} else {
				// 更新cb的offset
				cb-&gt;u.c.offset += event.res;
				cbs[nr_cbs++] = cb;
			}
		}

		if (nr_cbs) {
			// 继续接收数据
			io_submit(ctx, nr_cbs, cbs);
		}
	}
	return 0;
}</pre>
</div>
<p>运行
<div class="pre">
<pre>
$ truncate foo.txt -s 100K
$ truncate foo2.txt -s 200K
$ g++ -O3 libaio_simple.cc -laio &amp;&amp; ./a.out foo.txt foo2.txt
3 received 32768 bytes
4 received 32768 bytes
3 received 32768 bytes
4 received 32768 bytes
3 received 32768 bytes
4 received 32768 bytes
3 received 4096 bytes
3 done.
4 received 32768 bytes
4 received 32768 bytes
4 received 32768 bytes
4 received 8192 bytes
4 done.
</pre>
</div>
<h3>四、其它</h3>
<p>这里有个问题，因为O_DIRECT跳过系统缓存，直接从磁盘读取，对于读写来讲是个大问题。要自已实现缓存，需要一堆东西要啃，而且还不一定写得好。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jiangmiao.org/blog/2290.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>nodejs V8 Persistent句柄与GC</title>
		<link>http://www.jiangmiao.org/blog/2247.html</link>
		<comments>http://www.jiangmiao.org/blog/2247.html#comments</comments>
		<pubDate>Sat, 23 Jul 2011 17:36:01 +0000</pubDate>
		<dc:creator>JiangMiao</dc:creator>
				<category><![CDATA[javascript]]></category>

		<guid isPermaLink="false">http://www.jiangmiao.org/blog/?p=2247</guid>
		<description><![CDATA[在nodejs中，常常会遇到ObjectWrap的C++ Module，即用一个Persistent句柄引用一个携带C/C++指针的对象，并设定该Persistent句柄的WeakCallback，当Persistent被孤立时，删除指针，并Dispose句柄。一般来说凡是C++/Native的Module（如PostgreSQL，Memcache等等)的都会有Persistent释放问题。 测试发现，因为GC的延迟常常会使得有效的指针堆积如山，由heap.cc可以得知V8的在台式机上的GC策略为 reserved_semispace_size_(16*MB), max_semispace_size_(16*MB), //GC最大阈值为16M initial_semispace_size_(1*MB), //初使的GC的阈值为1M max_old_generation_size_(1*GB), //最大内存消耗 max_executable_size_(256*MB), code_range_size_(512*MB), 1. 测试代码1 对于如下C++0x测试代码 1 #include &#60;v8.h&#62; #include &#60;stdio.h&#62; #include &#60;sys/time.h&#62; using namespace v8; class Foo { public: static int total; static int number; static int last; Foo(); ~Foo(); &#8230; <a href="http://www.jiangmiao.org/blog/2247.html">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>在nodejs中，常常会遇到ObjectWrap的C++ Module，即用一个Persistent句柄引用一个携带C/C++指针的对象，并设定该Persistent句柄的WeakCallback，当Persistent被孤立时，删除指针，并Dispose句柄。一般来说凡是C++/Native的Module（如PostgreSQL，Memcache等等)的都会有Persistent释放问题。</p>
<p>测试发现，因为GC的延迟常常会使得有效的指针堆积如山，由heap.cc可以得知V8的在台式机上的GC策略为
<div class="pre">
<pre>
      reserved_semispace_size_(16*MB),
      max_semispace_size_(16*MB), //GC最大阈值为16M
      initial_semispace_size_(1*MB), //初使的GC的阈值为1M
      max_old_generation_size_(1*GB), //最大内存消耗
      max_executable_size_(256*MB),
      code_range_size_(512*MB),
</pre>
</div>
<h4>1. 测试代码1</h4>
<p>对于如下C++0x测试代码 1
<div class="pre">
<pre class="cpp" name="code">#include &lt;v8.h&gt;
#include &lt;stdio.h&gt;
#include &lt;sys/time.h&gt;

using namespace v8;
class Foo
{
    public:
	static int total;
	static int number;
	static int last;

	Foo();
	~Foo();
};

int Foo::total  = 1;
int Foo::number = 1;
int Foo::last = 1;

Foo::Foo()
{
	if (last &gt; number) {
		printf(&quot;creating from id %d\n&quot;, number);
	}
	last = number;
	++number;
	++total;
	// 加上下面这条似乎更合理，不过对于没有成员变量的类来说有没有都无感觉。
	// 2011-08-13 补充，使用sizeof(Foo) 1字节，并不正确，详见文尾补充
	V8::AdjustAmountOfExternalAllocatedMemory(sizeof(Foo));
}

Foo::~Foo()
{
	if (last&lt;number) {
		printf(&quot;sweeping from id %d\n&quot;, number);
	}
	last = number;
	--number;
	V8::AdjustAmountOfExternalAllocatedMemory(-sizeof(Foo));
}

long long microtime()
{
	timeval tv;
	gettimeofday(&amp;tv, NULL);
	return (long long)tv.tv_sec * 1000 + tv.tv_usec / 1000;
}

int main(int argc, char *argv[])
{
	V8::SetFlagsFromCommandLine(&amp;argc, argv, true);

	HandleScope scope;
	auto context = Context::New();
	Context::Scope context_scope(context);

	auto object_template = ObjectTemplate::New();
	object_template-&gt;SetInternalFieldCount(1);

	auto start = microtime();
	int times = 2e8;
	for (int i=0; i&lt;times; ++i) {
		HandleScope scope;
		auto object = object_template-&gt;NewInstance();
		auto foo = new Foo();

		// 把foo可入到object，使得在任何时候都可能通过对象object得到foo的指针。
		// 这句也可简写成object-&gt;SetPointerInInternalField(0, foo);
		object-&gt;SetInternalField(0, External::New(foo));

		// 创建一个Persistent句柄监视object的引用状况，
		// 当object不被任何对象引用时，删除foo与该句柄。
		Persistent&lt;Object&gt;::New(object).MakeWeak(foo, [](Persistent&lt;Value&gt; value, void *data) {
			delete (Foo*)data;
			value.Dispose();
		});
		if (i%(int)1e6 == 0) {
			int speed = i / (microtime() - start);
			printf(&quot;Speed: %d\n&quot;, speed);
		}
	}

	context.Dispose();
	return 0;
}</pre>
</div>
<p>编译
<div class="pre">
<pre>
$ g++ -std=c++0x -O3 gc_test.cc -lv8
</pre>
</div>
<h4>2. 使用默认策略</h4>
<p>max-semispace-size 16M<br />max-old-generation-size 1G<br />如果使用默认策略，输出结果
<div class="pre">
<pre>
$ ./a.out  --trace-gc
Speed: 0
Scavenge 0.9 -&gt; 0.8 MB, 5 ms.
Scavenge 1.2 -&gt; 1.2 MB, 6 ms.
Scavenge 1.6 -&gt; 1.6 MB, 6 ms.
Scavenge 2.3 -&gt; 2.3 MB, 13 ms.
sweeping from id 114428
Mark-sweep 3.1 -&gt; 3.0 MB, 35 / 74 ms.
creating from id 1
Scavenge 5.0 -&gt; 5.0 MB, 25 ms.
...
...
Scavenge 46.4 -&gt; 46.4 MB, 89 ms.
Speed: 186
Scavenge 52.4 -&gt; 52.4 MB, 103 ms.
Scavenge 58.4 -&gt; 58.4 MB, 112 ms.
...
...
Scavenge 106.4 -&gt; 106.4 MB, 170 ms.
sweeping from id 3233110
Mark-sweep 112.4 -&gt; 74.4 MB, 998 / 1999 ms.
creating from id 1
Speed: 182
Scavenge 82.4 -&gt; 82.4 MB, 89 ms.
Scavenge 88.4 -&gt; 88.4 MB, 94 ms.
Scavenge 94.4 -&gt; 94.4 MB, 104 ms.
</pre>
</div>
<p>可以发现，运行不多时，需积压了323万个Persistent才进行一次Mark-sweep，耗时2s，如果对于服务器让其挂起2S进行GC，显然是不行的。而且会不断的消耗内存，直到默认的1GB为止，但奇怪的是在1GB后Mark sweep释放也不会使物理占用内存下降。<br />
<h4>3. 限制max-old-generation-size为20</h4>
<p>max-old-generation-size的参数在命令行下为max-old-space-size，单位M<br />加入参数 &#8211;max-old-space-size=20 限制space的大小为20M
<div class="pre">
<pre>
$ ./a.out --trace-gc --max-old-space-size=20
Speed: 0
Scavenge 0.9 -&gt; 0.8 MB, 5 ms.
Scavenge 1.2 -&gt; 1.2 MB, 6 ms.
Scavenge 1.6 -&gt; 1.6 MB, 6 ms.
Scavenge 2.3 -&gt; 2.3 MB, 13 ms.
sweeping from id 114428
Mark-sweep 3.1 -&gt; 3.0 MB, 35 / 75 ms.
creating from id 1
Scavenge 5.0 -&gt; 5.0 MB, 26 ms.
Scavenge 6.5 -&gt; 6.5 MB, 24 ms.
Scavenge 9.5 -&gt; 9.5 MB, 52 ms.
Scavenge 12.5 -&gt; 12.5 MB, 54 ms.
sweeping from id 677206
Mark-sweep 18.5 -&gt; 15.9 MB, 213 / 458 ms.
creating from id 1
Speed: 190
sweeping from id 349526
Mark-sweep 23.9 -&gt; 8.4 MB, 111 / 304 ms.
creating from id 1
sweeping from id 349526
Mark-sweep 16.4 -&gt; 8.4 MB, 116 / 284 ms.
creating from id 1
sweeping from id 349526
Mark-sweep 16.4 -&gt; 8.4 MB, 111 / 277 ms.
creating from id 1
Speed: 190
sweeping from id 349526
Mark-sweep 16.4 -&gt; 8.4 MB, 108 / 273 ms.
creating from id 1
</pre>
</div>
<p>发现当使用超过20M后就进行了global GC模式。每次sweep 200ms也到了可接受范围。<br />
<h4>4. 设置&#8211;gc-global强制MarkSweep与max-semispace-size为2048K</h4>
<p>max-semispace-size对应的命令行设置参数为&#8211;max-new-space-size，单位K<br />测试2、通过设置参数&#8211;gc-global 强制每次都执行Mark-sweep 与 &#8211;max-new-space-size 缩小最大阈值
<div class="pre">
<pre>
$ ./a.out --trace-gc --max-new-space-size=2048 --gc-global
Speed: 0
sweeping from id 16124
Mark-sweep 0.7 -&gt; 0.7 MB, 6 / 15 ms.
creating from id 1
sweeping from id 21846
Mark-sweep 1.2 -&gt; 0.8 MB, 8 / 20 ms.
creating from id 1
sweeping from id 21846
Mark-sweep 1.3 -&gt; 0.8 MB, 8 / 20 ms.
creating from id 1
sweeping from id 43692
Mark-sweep 1.8 -&gt; 1.3 MB, 17 / 39 ms.
creating from id 2
sweeping from id 43692
Mark-sweep 2.3 -&gt; 1.3 MB, 17 / 39 ms.
creating from id 1
sweeping from id 43692
Speed: 186
</pre>
</div>
<p>从配合&#8211;gc-global情况来看，内存和GC时间都控制在一个很不错的水平，但尚不清楚，低semispace-size会有何影响，</p>
<p>但对于C/C++程序员来说，对于Persistent对象不交给GC而手动进行及时释放是最好的选择，避免了这样那样的GC问题。可惜nodejs缺少标准，而且不规范的native module过份依赖GC，与C++对象关联的ObjectWrap无法得到很好的释放，如果光占用内存还好，要是还占用描述符等系统资源，那等积压了数十万个才到GC时释放就晚了。<br />
<h4>5. 其它测试</h4>
<p>另外打算测试下 <a href="http://www.tabex.org/archives/703" target="_blank">小窥nodejs</a> 一文中的md5代码，竟发现代码在0.4.9中卡壳。升到git最新的0.5.3-pre也一样，
<div class="pre">
<pre>
var crypto = require(&#039;crypto&#039;);
var mymd5 = function(str, encoding){
  return crypto
  .createHash(&#039;md5&#039;)
  .update(str)
  .digest(encoding || &#039;hex&#039;);
};

while(1){
  console.info(mymd5(&quot;&quot; + parseInt(Math.random() * 100000)));
}
</pre>
</div>
<p>但用d8代替nodejs运行，一切正常。<br />对于代码
<div class="pre">
<pre>
if(typeof(print)==&#039;undefined&#039;) {
  print = console.info

}

i = 0;
while(true){
  ++i;
  print(i);
}
</pre>
</div>
<p>也会卡壳，似乎是过由快的输出函数调用导致。<br />修改代码至
<div class="pre">
<pre>
if(typeof(print)==&#039;undefined&#039;) {
  print = console.info

}

i = 0;
while(true){
  ++i;
  if (i%100 ==0)
    print(i);
}
</pre>
</div>
<p>就不再卡壳了。<br />原代码修改为
<div class="pre">
<pre>
if(typeof(print)==&#039;undefined&#039;) {
  print = console.info

}

var crypto = require(&#039;crypto&#039;);
var mymd5 = function(str, encoding){
  return crypto
  .createHash(&#039;md5&#039;)
  .update(str)
  .digest(encoding || &#039;hex&#039;);
};

i=0;
while(1){
  mymd5(&quot;&quot; + parseInt(Math.random() * 100000));
  ++i;
  if (i%100000 == 0) {
    print(i);
  }
}
</pre>
</div>
<p>若用max-new-space-size配gc-global参数，的确能把内存控制在一个合理的范围。
<div class="pre">
<pre>
$ node --trace-gc --max-new-space-size=2048 --gc-global md5.js
Mark-sweep 1.5 -&gt; 1.2 MB, 7 ms.
Mark-sweep 1.9 -&gt; 1.5 MB, 1 / 11 ms.
...
...
Mark-sweep 2.9 -&gt; 1.9 MB, 4 / 20 ms.
100000
Mark-sweep 2.9 -&gt; 1.9 MB, 4 / 20 ms.
...
...
Mark-sweep 2.9 -&gt; 1.9 MB, 4 / 19 ms.
200000
Mark-sweep 2.9 -&gt; 1.9 MB, 4 / 19 ms.
Mark-sweep 2.9 -&gt; 1.9 MB, 4 / 18 ms.
Mark-sweep 2.9 -&gt; 1.9 MB, 4 / 18 ms.
Mark-sweep 2.9 -&gt; 1.9 MB, 4 / 20 ms.
Mark-sweep 2.9 -&gt; 1.9 MB, 4 / 19 ms.
</pre>
</div>
<p>再对照没有Persistent句柄的脚本
<div class="pre">
<pre>
if(typeof(print)==&#039;undefined&#039;) {
  print = console.info
}

i=0;
while(1){
  str = &quot;hello world&quot; + i
  ++i;
  if (i%1000000 == 0) {
    print(i);
  }
}
</pre>
</div>
<p>虽然同样产生了大量的string对象，但因为对象都是Local对象，因此内存很好的得到了回收。
<div class="pre">
<pre>
$ node --trace-gc md5.js
Scavenge 1.5 -&gt; 1.3 MB, 2 ms.
Scavenge 1.8 -&gt; 1.6 MB, 2 ms.
Scavenge 2.0 -&gt; 1.8 MB, 2 ms.
...
...
Scavenge 5.8 -&gt; 2.1 MB, 2 ms.
Scavenge 5.8 -&gt; 2.1 MB, 2 ms.
Scavenge 5.8 -&gt; 2.1 MB, 2 ms.
1000000
Scavenge 5.8 -&gt; 2.1 MB, 2 ms.
Scavenge 5.8 -&gt; 2.1 MB, 2 ms.
...
...
Scavenge 5.8 -&gt; 2.1 MB, 2 ms.
Scavenge 9.8 -&gt; 2.1 MB, 2 ms.
2000000
Scavenge 9.8 -&gt; 2.1 MB, 2 ms.
Scavenge 9.8 -&gt; 2.1 MB, 2 ms.
...
...
Scavenge 9.8 -&gt; 2.1 MB, 2 ms.
3000000
Scavenge 9.8 -&gt; 2.1 MB, 2 ms.
...
...
Scavenge 9.8 -&gt; 2.1 MB, 2 ms.
5000000
Scavenge 9.8 -&gt; 2.1 MB, 2 ms.
Scavenge 9.8 -&gt; 2.1 MB, 2 ms.
Scavenge 9.8 -&gt; 2.1 MB, 2 ms.
</pre>
</div>
<p>对比string很明显，crypto制造的大量Persistent句柄，且没有手动释放，要等到GC Mark-sweep才能回收，就如测试代码一一样产生了越来越多的对象，V8又看到对象多多，不断的加大内存需求，直到默认的1G。<br />另外，新版的crypto似乎修正了不断侵食内存的问题。<br />
<h4>6. 小结</h4>
<p>要解决Persistent问题，方法有3<br />1、如本文所述，限制阈值，强制global gc<br />2、规范nodejs module，及时释放Persistent相关对象。<br />3、改进V8 GC策略</p>
<p>方法1,2可行性比较高。<br />如果遇到不断侵食内存的问题module，那只能使用方法1了。<br />
<h4>7. 其它问题：</h4>
<p>暂时不知道原因的问题，等路过的高人指点：<br />问题：使用默认策略测试代码1 Mark Sweep为什么物理内存还是占有950M以上。是V8内存策略还是Persistent的MakeWeak调用方法不正确？</p>
<p>===2011-08-13 补充==<br />知道了，即使是空对象也是有大小的，包括一些内存分配信息等，如果像文中例子使用sizeof(Foo) 1字节，是不正确的。分配new一个对象将占多少内存，不用深究具体数值，一定不大，用最大可能占用额然内存128字节限定，就能把内存控制在一个合理的范围。
<div class="pre">
<pre>
	// 加上下面这条似乎更合理，不过对于没有成员变量的类来说有没有都无感觉。
-	V8::AdjustAmountOfExternalAllocatedMemory(sizeof(Foo));
+	V8::AdjustAmountOfExternalAllocatedMemory(128);  

-	V8::AdjustAmountOfExternalAllocatedMemory(-sizeof(Foo));
+	V8::AdjustAmountOfExternalAllocatedMemory(-128);
</pre>
</div>
<p>输出
<div class="pre">
<pre>
sweeping from id 124978
Mark-sweep 11.2 -&gt; 3.2 MB, 85 / 149 ms.
creating from id 2
Speed: 167
sweeping from id 349436
Mark-sweep 11.2 -&gt; 8.4 MB, 235 / 474 ms.
creating from id 1
sweeping from id 124985
Mark-sweep 11.2 -&gt; 3.2 MB, 84 / 147 ms.
creating from id 2
</pre>
</div>
<p>锁定到了 11.2M</p>
<p>== 2011-08-16 补充 ==<br />在程序中可以通过函数 V8::LowMemoryNotification 进行强行GC</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jiangmiao.org/blog/2247.html/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>javascript V8惊人的性能</title>
		<link>http://www.jiangmiao.org/blog/2195.html</link>
		<comments>http://www.jiangmiao.org/blog/2195.html#comments</comments>
		<pubDate>Tue, 19 Jul 2011 17:18:02 +0000</pubDate>
		<dc:creator>JiangMiao</dc:creator>
				<category><![CDATA[C/C++]]></category>
		<category><![CDATA[javascript]]></category>

		<guid isPermaLink="false">http://www.jiangmiao.org/blog/?p=2195</guid>
		<description><![CDATA[今天测试了一下V8，虽然一直听说和感觉到V8快，但测试后发现性能超过C++ STL，甚至超过了C函数。着实惊人。 一、测试代码： 1. C++：test.cc #include &#60;sys/time.h&#62; #include &#60;cstdlib&#62; #include &#60;cstdio&#62; #include &#60;vector&#62; #include &#60;list&#62; #include &#60;string&#62; #include &#60;map&#62; #include &#60;unordered_map&#62; #include &#60;boost/asio/detail/hash_map.hpp&#62; #include &#60;string.h&#62; using namespace std; long long microtime() { timeval tv; gettimeofday(&#38;tv, NULL); return (long long)tv.tv_sec * &#8230; <a href="http://www.jiangmiao.org/blog/2195.html">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>今天测试了一下V8，虽然一直听说和感觉到V8快，但测试后发现性能超过C++ STL，甚至超过了C函数。着实惊人。<br />
<h3>一、测试代码：</h3>
<h4>1. C++：test.cc</h4>
<div class="pre">
<pre>
#include &lt;sys/time.h&gt;

#include &lt;cstdlib&gt;
#include &lt;cstdio&gt;

#include &lt;vector&gt;
#include &lt;list&gt;
#include &lt;string&gt;
#include &lt;map&gt;
#include &lt;unordered_map&gt;
#include &lt;boost/asio/detail/hash_map.hpp&gt;
#include &lt;string.h&gt;
using namespace std;

long long microtime()
{
	timeval tv;
	gettimeofday(&amp;tv, NULL);
	return (long long)tv.tv_sec * 1000 + tv.tv_usec / 1000;
}

#define START() long long start = microtime();
#define FINISH(title) printf(&quot;%s %lld\n&quot;, title, times / (microtime() - start));
#define BENCHMARK for(int i=0; i&lt;times; ++i)

#define BIG_INTERVAL 60 * 60 * 1000
#define SMALL_INTERVAL 1 * 1000
inline char *my_itoa(int n)
{
	bool is_neg = false;
	if (n&lt;0) {
		is_neg = true;
		n = -n;
	}
	static char buf[16];
	char * last = buf + 15;
	*last = 0;
	do {
		*(--last) = &#039;0&#039; + n % 10;
		n /= 10;
	} while(n);
	if (is_neg) {
		*(--last) = &#039;-&#039;;
	}
	return last;
}

int main(int argc, char *argv[])
{
	int times = 1e6;
	{
		START();
		char buf[64];
		BENCHMARK {
			sprintf(buf, &quot;%da&quot;, i);
		}
		FINISH(&quot;i+a&quot;);
	}

	{
		START();
		char buf[64];
		BENCHMARK {
			sprintf(buf, &quot;%sa&quot;, my_itoa(i));
		}
		FINISH(&quot;sprintf without locale&quot;);
	}

	{
		START();
		char buf[64];
		BENCHMARK {
			char *dest = buf;
			dest = stpcpy(dest, &quot;a&quot;);
			dest = stpcpy(dest, my_itoa(i));
		}
		FINISH(&quot;strpcpy&quot;);
	}

	{
		START();
		vector&lt;int&gt; vs;
		BENCHMARK {
			vs.push_back(i);
		}
		FINISH(&quot;array int&quot;);

	}

	{
		START();
		vector&lt;int&gt; vs;
		BENCHMARK {
			vs.push_back(9999);
		}
		FINISH(&quot;array int static&quot;);

	}

	{
		START();
		list&lt;int&gt; ls;
		BENCHMARK {
			ls.push_back(9999);
		}
		FINISH(&quot;array list static&quot;);

	}

	{
		START();
		vector&lt;string&gt; vs;
		char buf[64];
		BENCHMARK {
			sprintf(buf, &quot;%d&quot;, i);
			vs.push_back(buf);
		}
		FINISH(&quot;array string&quot;);

	}

	{
		START();
		vector&lt;string&gt; vs;
		char buf[64];
		BENCHMARK {
			vs.push_back(&quot;hello world&quot;);
		}
		FINISH(&quot;array string static&quot;);

	}

	{
		START();
		string a = &quot;hello&quot;;
		string b = &quot;world&quot;;
		string c;
		BENCHMARK {
			c = a + b;
		}
		FINISH(&quot;string a+b&quot;);
	}

	unordered_map&lt;int, int&gt; um;
	{
		START()
		BENCHMARK {
			um[i] = i;
		}
		FINISH(&quot;unordered map&quot;);
	}

	boost::asio::detail::hash_map&lt;int, int&gt; hm;
	{
		START()
		BENCHMARK {
			hm.insert(make_pair(i, i));
		}
		FINISH(&quot;asio hash map&quot;);
	}

	map&lt;int, int&gt; m;
	{
		START()
		BENCHMARK {
			m[i] = i;
		}
		FINISH(&quot;map&quot;);
	}
	return 0;
}
</pre>
</div>
<h4>2. CoffeeScript：test.coffee</h4>
<div class="pre">
<pre>
benchmark = (title, callback) -&gt;
  start = Date.now()
  times = 1e6
  for i in [1..times]
    callback(i)
  console.info title, times / (Date.now() - start)

benchmark &#039;i+a&#039;, (i)-&gt;
  i+&#039;a&#039;

a=[]
benchmark &#039;array int&#039;, (i)-&gt;
  a.push i

a=[]
benchmark &#039;array int static&#039;, (i)-&gt;
  a.push 9999

a=[]
benchmark &#039;array string&#039;, (i)-&gt;
  a.push i+&#039;&#039;

a=[]
benchmark &#039;array string static&#039;, (i)-&gt;
  a.push &#039;hello world&#039;

benchmark &#039;string a+b&#039;, (i)-&gt;
  c = &#039;hello&#039;+&#039;world&#039;

a={}
benchmark &#039;map&#039;, (i)-&gt;
  a[i] = i
</pre>
</div>
<h3>二、测试环境</h3>
<div class="pre">
<pre>
Linux myhost 2.6.36-ARCH
#1 SMP PREEMPT Mon Jan 24 18:34:55 UTC 2011 i686
Intel(R) Atom(TM) CPU D510 @ 1.66GHz GenuineIntel GNU/Linux

node v0.4.9
gcc 版本 4.6.1 (GCC)
v8 3.2.10.2
</pre>
</div>
<h3>三、测试过程</h3>
<p>C++：
<div class="pre">
<pre>
$ g++ -O3   -c -o test.o test.cc
$ g++   test.o   -o test
i+a 1642
array int 52631
array static 58823
array string 881
array string static 2272
string a+b 1594
map 1109
</pre>
</div>
<p>javascript：
<div class="pre">
<pre>
$ coffee test.coffee
i+a 1937.984496124031
array int 14492.753623188406
array int static 16393.44262295082
array string 1564.9452269170579
array string static 11111.111111111111
string a+b 7042.2535211267605
map 8928.57142857143
</pre>
</div>
<h3>四、测试结果</h3>
<p>单位：次数/毫秒<br />
<table>
<tr>
<td width="33.33%"></td>
<td width="33.33%">C++</td>
<td width="33.33%">V8</td>
</tr>
<tr>
<td width="33.33%">i+a</td>
<td width="33.33%">1642</td>
<td width="33.33%">1937 &#8211; 117%</td>
</tr>
<tr>
<td width="33.33%">sprintf without locale</td>
<td width="33.33%">1834</td>
<td width="33.33%">1937 &#8211; 105%</td>
</tr>
<tr>
<td width="33.33%">strpcpy</td>
<td width="33.33%">9615</td>
<td width="33.33%">1937 &#8211; 20%</td>
</tr>
<tr>
<td width="33.33%">array int</td>
<td width="33.33%">52631</td>
<td width="33.33%">14492 &#8211; 27%</td>
</tr>
<tr>
<td width="33.33%">array int static</td>
<td width="33.33%">58823</td>
<td width="33.33%">16393 &#8211; 27%</td>
</tr>
<tr>
<td width="33.33%">array string</td>
<td width="33.33%">881</td>
<td width="33.33%">1564 &#8211; 177%</td>
</tr>
<tr>
<td width="33.33%">array string static</td>
<td width="33.33%">2272</td>
<td width="33.33%">11111 &#8211; 489%</td>
</tr>
<tr>
<td width="33.33%">string a+b</td>
<td width="33.33%">1594</td>
<td width="33.33%">7042 &#8211; 441%</td>
</tr>
<tr>
<td width="33.33%">map</td>
<td width="33.33%">1109</td>
<td width="33.33%">8928 &#8211; 805%</td>
</tr>
<tr>
<td width="33.33%">unordered_map</td>
<td width="33.33%">2941</td>
<td width="33.33%">8928 &#8211; 306%</td>
</tr>
<tr>
<td width="33.33%">asio hash map</td>
<td width="33.33%">2525</td>
<td width="33.33%">8928 &#8211; 354%</td>
</tr>
</table>
<h3>五、测试总结</h3>
<p>V8的字符串转换居然超过了C函数sprintf性能。<br />STL的vector性能依然强劲，<br />但string与map性能远不及V8，本次测试中拖了后腿。</p>
<p>从测试来看，如果不打算用原生代码C/C++写nodejs扩展，还是用javascript来得实惠，若用STL说不定性能不升反降。<br />
<h3>六、其它</h3>
<p><a href="http://shootout.alioth.debian.org/u32/javascript.php" target="_blank">The Computer Language Benchmarks Game</a>提供了各种语言的性能大小等比较，但该网站的测试代码质量和注重方向参差不齐，总得来看V8的性能约为C的1/3。内存使用为5倍，代码量为1/3，作为最快的动态语言，比起PHP，Python，Ruby等可谓是相当出众。<br />
<h3>七、相关链接</h3>
<p><a href="http://code.google.com/p/v8/" target="_blank">V8官网</a><br /><a href="http://code.google.com/intl/zh-CN/apis/v8/design.html" target="_blank">V8设计元素</a><br /><a href="http://www.greenpublishers.com/neat/200901/3coverstory.pdf" target="_blank">为什么V8这么快.pdf</a></p>
<p>备注：因为内存管理模型不同，V8是由垃圾回收控制，而C++是立即是放，所以含有内存释放相关的测试结果并非完全精确，仅供参考。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jiangmiao.org/blog/2195.html/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
	</channel>
</rss>

<!-- Dynamic page generated in 0.431 seconds. -->
<!-- Cached page generated by WP-Super-Cache on 2012-01-22 14:30:16 -->

