<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>IT技术博客大学习</title>
	<link>http://www.blogread.cn/it/</link> 
	<description>IT技术博客大学习 共学习 共进步</description>
	<language>zh-cn</language>
	<pubDate>Wed, 30 May 2012 20:00:23 +0800</pubDate>
	<copyright>Copyright (C) 2009 - 2012 IT技术博客大学习 - 本页面所有内容，未经blogread.cn许可，欢迎转载，但请注明出处</copyright>
	<generator>yayu</generator>
	<lastBuildDate>Wed, 30 May 2012 20:00:23 +0800</lastBuildDate>

	<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/blogreadIT" /><feedburner:info uri="blogreadit" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><feedburner:feedFlare href="http://add.my.yahoo.com/rss?url=http%3A%2F%2Ffeeds.feedburner.com%2FblogreadIT" src="http://us.i1.yimg.com/us.yimg.com/i/us/my/addtomyyahoo4.gif">Subscribe with My Yahoo!</feedburner:feedFlare><feedburner:feedFlare href="http://www.newsgator.com/ngs/subscriber/subext.aspx?url=http%3A%2F%2Ffeeds.feedburner.com%2FblogreadIT" src="http://www.newsgator.com/images/ngsub1.gif">Subscribe with NewsGator</feedburner:feedFlare><feedburner:feedFlare href="http://feeds.my.aol.com/add.jsp?url=http%3A%2F%2Ffeeds.feedburner.com%2FblogreadIT" src="http://o.aolcdn.com/favorites.my.aol.com/webmaster/ffclient/webroot/locale/en-US/images/myAOLButtonSmall.gif">Subscribe with My AOL</feedburner:feedFlare><feedburner:feedFlare href="http://www.bloglines.com/sub/http://feeds.feedburner.com/blogreadIT" src="http://www.bloglines.com/images/sub_modern11.gif">Subscribe with Bloglines</feedburner:feedFlare><feedburner:feedFlare href="http://www.netvibes.com/subscribe.php?url=http%3A%2F%2Ffeeds.feedburner.com%2FblogreadIT" src="http://www.netvibes.com/img/add2netvibes.gif">Subscribe with Netvibes</feedburner:feedFlare><feedburner:feedFlare href="http://fusion.google.com/add?feedurl=http%3A%2F%2Ffeeds.feedburner.com%2FblogreadIT" src="http://buttons.googlesyndication.com/fusion/add.gif">Subscribe with Google</feedburner:feedFlare><feedburner:feedFlare href="http://www.pageflakes.com/subscribe.aspx?url=http%3A%2F%2Ffeeds.feedburner.com%2FblogreadIT" src="http://www.pageflakes.com/ImageFile.ashx?instanceId=Static_4&amp;fileName=ATP_blu_91x17.gif">Subscribe with Pageflakes</feedburner:feedFlare><feedburner:feedFlare href="http://www.plusmo.com/add?url=http%3A%2F%2Ffeeds.feedburner.com%2FblogreadIT" src="http://plusmo.com/res/graphics/fbplusmo.gif">Subscribe with Plusmo</feedburner:feedFlare><feedburner:feedFlare href="http://www.thefreedictionary.com/_/hp/AddRSS.aspx?http%3A%2F%2Ffeeds.feedburner.com%2FblogreadIT" src="http://img.tfd.com/hp/addToTheFreeDictionary.gif">Subscribe with The Free Dictionary</feedburner:feedFlare><feedburner:feedFlare href="http://www.bitty.com/manual/?contenttype=rssfeed&amp;contentvalue=http%3A%2F%2Ffeeds.feedburner.com%2FblogreadIT" src="http://www.bitty.com/img/bittychicklet_91x17.gif">Subscribe with Bitty Browser</feedburner:feedFlare><feedburner:feedFlare href="http://www.newsalloy.com/?rss=http%3A%2F%2Ffeeds.feedburner.com%2FblogreadIT" src="http://www.newsalloy.com/subrss3.gif">Subscribe with NewsAlloy</feedburner:feedFlare><feedburner:feedFlare href="http://www.live.com/?add=http%3A%2F%2Ffeeds.feedburner.com%2FblogreadIT" src="http://tkfiles.storage.msn.com/x1piYkpqHC_35nIp1gLE68-wvzLZO8iXl_JMledmJQXP-XTBOLfmQv4zhj4MhcWEJh_GtoBIiAl1Mjh-ndp9k47If7hTaFno0mxW9_i3p_5qQw">Subscribe with Live.com</feedburner:feedFlare><feedburner:feedFlare href="http://mix.excite.eu/add?feedurl=http%3A%2F%2Ffeeds.feedburner.com%2FblogreadIT" src="http://image.excite.co.uk/mix/addtomix.gif">Subscribe with Excite MIX</feedburner:feedFlare><feedburner:feedFlare href="http://download.attensa.com/app/get_attensa.html?feedurl=http%3A%2F%2Ffeeds.feedburner.com%2FblogreadIT" src="http://www.attensa.com/blogs/attensa/WindowsLiveWriter/BadgeredintoBadges_10C02/attensa_feed_button5.gif">Subscribe with Attensa for Outlook</feedburner:feedFlare><feedburner:feedFlare href="http://www.webwag.com/wwgthis.php?url=http%3A%2F%2Ffeeds.feedburner.com%2FblogreadIT" src="http://www.webwag.com/images/wwgthis.gif">Subscribe with Webwag</feedburner:feedFlare><feedburner:feedFlare href="http://www.podcastready.com/oneclick_bookmark.php?url=http%3A%2F%2Ffeeds.feedburner.com%2FblogreadIT" src="http://www.podcastready.com/images/podcastready_button.gif">Subscribe with Podcast Ready</feedburner:feedFlare><feedburner:feedFlare href="http://www.flurry.com/pushRssFeed.do?r=fb&amp;url=http%3A%2F%2Ffeeds.feedburner.com%2FblogreadIT" src="http://www.flurry.com/images/flurry_rss_logo2.gif">Subscribe with Flurry</feedburner:feedFlare><feedburner:feedFlare href="http://www.wikio.com/subscribe?url=http%3A%2F%2Ffeeds.feedburner.com%2FblogreadIT" src="http://www.wikio.com/shared/img/add2wikio.gif">Subscribe with Wikio</feedburner:feedFlare><feedburner:feedFlare href="http://www.dailyrotation.com/index.php?feed=http%3A%2F%2Ffeeds.feedburner.com%2FblogreadIT" src="http://www.dailyrotation.com/rss-dr2.gif">Subscribe with Daily Rotation</feedburner:feedFlare><feedburner:browserFriendly>本站主要收集了大量个人博客，从中我们可以互相学习，同时也看到和你一样的人是如何学习，如何进步的！</feedburner:browserFriendly><item>
		<title>如何熟悉一个开源项目？</title>
		<link>http://feedproxy.google.com/~r/blogreadIT/~3/49SRyOm0q0Q/article.php</link>
		<author>dennis</author>
		<pubDate>2012-05-28 13:34:20</pubDate>
		<category domain="http://blogread.cn/it/category.php?id=10">奋斗</category>
		<guid isPermaLink="false">http://blogread.cn/it/article.php?id=5415</guid>
		<comments>http://blogread.cn/it/article.php?id=5415#comment</comments>
		<description>&lt;p&gt;&lt;strong&gt;标签：&lt;/strong&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://blogread.cn/it/tags.php?tag=%E5%BC%80%E6%BA%90%E9%A1%B9%E7%9B%AE" target="_blank"&gt;开源项目&lt;/a&gt;&lt;/p&gt;&lt;P&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; 你有个任务，需要用到某个开源项目;或者老大交代你一个事情，让你去了解某个东西。怎么下手呢？如何开始呢？我的习惯是这样：&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;1.首先，查找和阅读该项目的博客和资料，通过google你能找到某个项目大体介绍的博客，快速阅读一下就能对项目的目的、功能、基本使用有个大概的了解。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;2.阅读项目的文档，重点关注类似&lt;STRONG&gt;Getting started、Example&lt;/STRONG&gt;之类的文档，从中学习如何下载、安装、甚至基本使用该项目所需要的知识。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;3.如果该项目有提供现成的example工程，首先尝试按照开始文档的介绍运行example，如果运行顺利，那么恭喜你顺利开了个好头;如果遇到问题，首先尝试在项目的&lt;STRONG&gt;FAQ&lt;/STRONG&gt;等文档里查找答案，再次，可以将问题(例如异常信息)当成关键词去搜索，查找相关的解决办法，你遇到了，别人一般也会遇到，热心的朋友会记录下解决的过程;最后，可以将问题提交到项目的邮件列表，请大家帮你看看。&lt;STRONG&gt;在没有成功运行example之前，不要尝试修改example。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/STRONG&gt;4.运行了第一个example之后，尝试根据你的理解和需要修改example，测试高级功能等。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;5.在了解基本使用后，需要开始深入的了解该项目。例如项目的配置管理、高级功能以及最佳实践。通常一个运作良好的项目会提供一份从浅到深的用户指南，你并不需要从头到尾阅读这份指南，根据时间和兴趣，特别是你自己任务的需要，重点阅读部分章节并做笔记(推荐evernote)。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;6.如果时间允许，尝试从源码构建该项目。通常开源项目都会提供一份构建指南，指导你如何搭建一个用于开发、调试和构建的环境。尝试构建一个版本。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;7.如果时间允许并且有兴趣，可以尝试阅读源码：&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(1)阅读源码之前，查看该项目是否提供架构和设计文档，阅读这些文档可以了解该项目的大体设计和结构，读源码的时候不会无从下手。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(2)阅读源码之前，一定要能构建并运行该项目，有个直观感受。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(3)阅读源码的第一步是抓主干，尝试理清一次正常运行的代码调用路径，这可以通过debug来观察运行时的变量和行为。修改源码加入日志和打印可以帮助你更好的理解源码。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(4)适当画图来帮助你理解源码，在理清主干后，可以将整个流程画成一张流程图或者标准的UML图，帮助记忆和下一步的阅读。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(5)挑选感兴趣的“枝干”代码来阅读，比如你对网络通讯感兴趣，就阅读网络层的代码，深入到实现细节，如它用了什么库，采用了什么设计模式，为什么这样做等。如果可以，debug细节代码。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(6)阅读源码的时候，重视单元测试，尝试去运行单元测试，基本上一个好的单元测试会将该代码的功能和边界描述清楚。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(7)在熟悉源码后，发现有可以改进的地方，有精力、有意愿可以向该项目的开发者提出改进的意见或者issue，甚至帮他修复和实现，参与该项目的发展。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;8.通常在阅读文档和源码之后，你能对该项目有比较深入的了解了，但是该项目所在领域，你可能还想搜索相关的项目和资料，看看有没有其他的更好的项目或者解决方案。在广度和深度之间权衡。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; 以上是我个人的一些习惯，我自己也并没有完全按照这个来，但是按照这个顺序，基本上能让你比较高效地学习和使用某个开源项目。&lt;IMG src="http://www.blogjava.net/killme2008/aggbug/378885.html" width=1 height=1&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;DIV align=right&gt;&lt;A style="TEXT-DECORATION: none" href="http://www.blogjava.net/killme2008/" target=_blank&gt;dennis&lt;/A&gt; 2012-05-22 23:12 &lt;A style="TEXT-DECORATION: none" href="http://www.blogjava.net/killme2008/archive/2012/05/22/378885.html#Feedback" target=_blank&gt;发表评论&lt;/A&gt;&lt;/DIV&gt;
				&lt;p&gt;&lt;strong&gt;您可能还对下面的文章感兴趣：&lt;/strong&gt;&lt;/p&gt;
				&lt;p&gt;很抱歉，暂时没有...... &lt;/p&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/IBo2nLqRRBQ99vCbSBZamyA2UWI/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/IBo2nLqRRBQ99vCbSBZamyA2UWI/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/IBo2nLqRRBQ99vCbSBZamyA2UWI/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/IBo2nLqRRBQ99vCbSBZamyA2UWI/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/blogreadIT/~4/49SRyOm0q0Q" height="1" width="1"/&gt;</description>
		<content><![CDATA[你有个任务，需要用到某个开源项目;或者老大交代你一个事情，让你去了解某个东西。怎么下手呢？如何开始呢？我的习惯是这样：1.首先，查找和阅读该项目的博客和资料，通过google你能找到某个项目大体介绍的博客，快速阅读一下就能对项目的目的、功能、基本使用有个大概的了解。2.阅读项目的文档，重点关注类似Getting started、Example之类的文档，从中学习如何下载、安装、甚至基本使用该项目所需要的知识。3.如果该项目有提供现成的example工程，首先尝试按照开始文档的介绍运行example，如果运行顺利，那么恭喜你顺利开了个好头;如果遇到问题，首先尝试在项目的FAQ等文档里查找答案，再次，可以将问题(例如异常信息)当成关键词去搜索，查找相关的解决办法，你遇到了，别人一般也会遇到，热心的朋友会记录下解决的过程;最后，可以将问题提交到项目的邮件列表，请大家帮你看看。]]></content>
	<feedburner:origLink>http://blogread.cn/it/article.php?id=5415</feedburner:origLink></item>
	<item>
		<title>Huffman 编码压缩算法</title>
		<link>http://feedproxy.google.com/~r/blogreadIT/~3/cIGY110O0Gc/article.php</link>
		<author>陈皓</author>
		<pubDate>2012-05-28 13:33:53</pubDate>
		<category domain="http://blogread.cn/it/category.php?id=9">算法</category>
		<guid isPermaLink="false">http://blogread.cn/it/article.php?id=5414</guid>
		<comments>http://blogread.cn/it/article.php?id=5414#comment</comments>
		<description>&lt;p&gt;&lt;strong&gt;标签：&lt;/strong&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://blogread.cn/it/tags.php?tag=Huffman" target="_blank"&gt;Huffman&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://blogread.cn/it/tags.php?tag=%E5%8E%8B%E7%BC%A9" target="_blank"&gt;压缩&lt;/a&gt;&lt;/p&gt;&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;前两天发布那个&lt;A title="rsync 的核心算法" href="http://coolshell.cn/articles/7425.html" target=_blank&gt;rsync算法&lt;/A&gt;后，想看看数据压缩的算法，知道一个经典的压缩算法Huffman算法。你应该听说过&amp;nbsp;&lt;A title="David Huffman" onclick="pageTracker._trackPageview(\'/outgoing/en.wikipedia.org/wiki/David_A._Huffman?referer=\');" href="http://en.wikipedia.org/wiki/David_A._Huffman" target=_blank&gt;David Huffman&lt;/A&gt;&amp;nbsp;和他的经典的压缩算法——&amp;nbsp;&lt;A onclick="pageTracker._trackPageview(\'/outgoing/en.wikipedia.org/wiki/Huffman_coding?referer=\');" href="http://en.wikipedia.org/wiki/Huffman_coding" target=_blank&gt;Huffman Code&lt;/A&gt;，这是一种通过字符出现频率，&lt;A onclick="pageTracker._trackPageview(\'/outgoing/en.wikipedia.org/wiki/Priority_queue?referer=\');" href="http://en.wikipedia.org/wiki/Priority_queue" target=_blank&gt;Priority Queue&lt;/A&gt;，和二叉树来进行的一种压缩算法，这种二叉树又叫Huffman二叉树 —— 一种带权重的树。但是网上查了一下，中文社区内好像没有把这个算法说得很清楚的文章，尤其是树的构造，而正好看到一篇国外的文章《&lt;A onclick="pageTracker._trackPageview(\'/outgoing/en.nerdaholyc.com/huffman-coding-on-a-string/?referer=\');" href="http://en.nerdaholyc.com/huffman-coding-on-a-string/" target=_blank&gt;A Simple Example of Huffman Code on a String&lt;/A&gt;》，其中的例子浅显易懂，相当不错，我就转了过来。注意，我没有对此文完全翻译。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;我们直接来看示例，如果我们需要来压缩下面的字符串：&lt;/P&gt;
&lt;P style="TEXT-ALIGN: center"&gt;&lt;STRONG&gt;&amp;nbsp;“beep boop beer!”&amp;nbsp;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;首先，我们先计算出每个字符出现的次数，我们得到下面这样一张表 :&lt;/P&gt;
&lt;TABLE style="WIDTH: 250px; HEIGHT: 200px"&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD&gt;字符&lt;/TD&gt;
&lt;TD&gt;次数&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;‘b’&lt;/TD&gt;
&lt;TD&gt;3&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;‘e’&lt;/TD&gt;
&lt;TD&gt;4&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;‘p’&lt;/TD&gt;
&lt;TD&gt;2&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;‘ ‘&lt;/TD&gt;
&lt;TD&gt;2&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;‘o’&lt;/TD&gt;
&lt;TD&gt;2&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;‘r’&lt;/TD&gt;
&lt;TD&gt;1&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;‘!’&lt;/TD&gt;
&lt;TD&gt;1&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 然后，我把把这些东西放到Priority Queue中(用出现的次数据当 priority)，我们可以看到，Priority Queue 是以Prioirry排序一个数组，如果Priority一样，会使用出现的次序排序：下面是我们得到的Priority Queue：&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;A href="http://coolshell.cn/wp-content/uploads/2012/05/coada1.png"&gt;&lt;IMG class="alignnone size-full wp-image-234 aligncenter" title=coada1 alt="" src="http://coolshell.cn/wp-content/uploads/2012/05/coada1.png" width=440 height=61&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;接下来就是我们的算法——把这个Priority&amp;nbsp;Queue 转成二叉树。我们始终从queue的头取两个元素来构造一个二叉树(第一个元素是左结点，第二个是右结点)，并把这两个元素的priority相加，并放回Priority中(再次注意，这里的Priority就是字符出现的次数)，然后，我们得到下面的数据图表：&lt;/P&gt;
&lt;P style="TEXT-ALIGN: center"&gt;&lt;A href="http://coolshell.cn/wp-content/uploads/2012/05/coada2.png"&gt;&lt;IMG class="alignnone size-full wp-image-239" title=coada2 alt="" src="http://coolshell.cn/wp-content/uploads/2012/05/coada2.png" width=411 height=151&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;同样，我们再把前两个取出来，形成一个Priority为2+2=4的结点，然后再放回Priority&amp;nbsp;Queue中 :&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;A href="http://coolshell.cn/wp-content/uploads/2012/05/coada31.png"&gt;&lt;IMG class="alignnone size-full wp-image-242 aligncenter" title=coada3 alt="" src="http://coolshell.cn/wp-content/uploads/2012/05/coada31.png" width=325 height=201&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;继续我们的算法(我们可以看到，这是一种自底向上的建树的过程)：&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;A href="http://coolshell.cn/wp-content/uploads/2012/05/coada4.png"&gt;&lt;IMG class="alignnone size-full wp-image-244 aligncenter" title=coada4 alt="" src="http://coolshell.cn/wp-content/uploads/2012/05/coada4.png" width=326 height=221&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;A href="http://coolshell.cn/wp-content/uploads/2012/05/coada5.png"&gt;&lt;IMG class="alignnone size-full wp-image-288 aligncenter" title=coada5 alt="" src="http://coolshell.cn/wp-content/uploads/2012/05/coada5.png" width=347 height=207&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;A href="http://coolshell.cn/wp-content/uploads/2012/05/coada61.png"&gt;&lt;IMG class="alignnone size-full wp-image-290 aligncenter" title=coada6 alt="" src="http://coolshell.cn/wp-content/uploads/2012/05/coada61.png" width=344 height=273&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;最终我们会得到下面这样一棵二叉树：&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;A href="http://coolshell.cn/wp-content/uploads/2012/05/arbore_final.png"&gt;&lt;IMG class="alignnone size-full wp-image-291 aligncenter" title=arbore_final alt="" src="http://coolshell.cn/wp-content/uploads/2012/05/arbore_final.png" width=452 height=304&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;此时，我们把这个树的左支编码为0，右支编码为1，这样我们就可以遍历这棵树得到字符的编码，比如：‘b’的编码是 00，’p\'的编码是101， ‘r’的编码是1000。&lt;STRONG&gt;我们可以看到出现频率越多的会越在上层，编码也越短，出现频率越少的就越在下层，编码也越长&lt;/STRONG&gt;。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;A href="http://coolshell.cn/wp-content/uploads/2012/05/arbore_final_numerotat.png"&gt;&lt;IMG class="alignnone size-full wp-image-292 aligncenter" title=arbore_final_numerotat alt="" src="http://coolshell.cn/wp-content/uploads/2012/05/arbore_final_numerotat.png" width=452 height=304&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;最终我们可以得到下面这张编码表：&lt;/P&gt;
&lt;TABLE style="WIDTH: 250px; HEIGHT: 200px"&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD&gt;字符&lt;/TD&gt;
&lt;TD&gt;编码&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;‘b’&lt;/TD&gt;
&lt;TD&gt;00&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;‘e’&lt;/TD&gt;
&lt;TD&gt;11&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;‘p’&lt;/TD&gt;
&lt;TD&gt;101&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;‘ ‘&lt;/TD&gt;
&lt;TD&gt;011&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;‘o’&lt;/TD&gt;
&lt;TD&gt;010&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;‘r’&lt;/TD&gt;
&lt;TD&gt;1000&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;‘!’&lt;/TD&gt;
&lt;TD&gt;1001&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 这里需要注意一点，当我们encode的时候，我们是按“bit”来encode，decode也是通过bit来完成，比如，如果我们有这样的bitset “1011110111″ 那么其解码后就是 “pepe”。所以，我们需要通过这个二叉树建立我们Huffman编码和解码的字典表。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;这里需要注意的一点是，我们的Huffman对各个字符的编码是不会冲突的，也就是说，&lt;STRONG&gt;不会存在某一个编码是另一个编码的前缀&lt;/STRONG&gt;，不然的话就会大问题了。因为encode后的编码是没有分隔符的。&lt;/P&gt;
&lt;P style="TEXT-ALIGN: left; PADDING-LEFT: 30px"&gt;于是，对于我们的原始字符串 &amp;nbsp;beep boop beer!&lt;/P&gt;
&lt;P style="TEXT-ALIGN: left; PADDING-LEFT: 30px"&gt;其对就能的二进制为 : 0110 0010 0110 0101 0110 0101 0111 0000 0010 0000 0110 0010 0110 1111 0110 1111 0111 0000 0010 0000 0110 0010 0110 0101 0110 0101 0111 0010 0010 0001&lt;/P&gt;
&lt;P style="TEXT-ALIGN: left; PADDING-LEFT: 30px"&gt;我们的Huffman的编码为： 0011 1110 1011 0001 0010 1010 1100 1111 1000 1001&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;从上面的例子中，我们可以看到被压缩的比例还是很可观的。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;作者给出了源码你可以看看( C99标准)&amp;nbsp;&lt;A onclick="pageTracker._trackPageview(\'/outgoing/en.nerdaholyc.com/wp-content/uploads/2012/05/huffman_string.zip?referer=\');" href="http://en.nerdaholyc.com/wp-content/uploads/2012/05/huffman_string.zip"&gt;Download the source files&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(全文完)&lt;/P&gt;
				&lt;p&gt;&lt;strong&gt;您可能还对下面的文章感兴趣：&lt;/strong&gt;&lt;/p&gt;
				&lt;p&gt;&lt;ol&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=3986" target="_blank"&gt;Doclist压缩方法简介&lt;/a&gt; [2011-07-12 13:43:11]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=3532" target="_blank"&gt;使用Google Closure Compiler全力压缩代码&lt;/a&gt; [2011-04-27 23:50:38]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=3051" target="_blank"&gt;数据压缩之范式HUFFMAN&lt;/a&gt; [2011-01-20 22:27:40]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=3030" target="_blank"&gt;mysql的数据压缩性能对比&lt;/a&gt; [2011-01-18 22:08:05]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=2772" target="_blank"&gt;JavaScript 压缩中的权衡&lt;/a&gt; [2010-11-30 22:48:25]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=2681" target="_blank"&gt;使用Apparat框架优化你的Flash&lt;/a&gt; [2010-11-11 19:42:16]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=2315" target="_blank"&gt;游戏资源的压缩、打包与补丁更新&lt;/a&gt; [2010-08-25 20:48:54]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=2175" target="_blank"&gt;windows下压缩包在linux解压乱码的解决办法&lt;/a&gt; [2010-08-06 09:44:09]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=1779" target="_blank"&gt;前端性能优化之Html压缩&lt;/a&gt; [2010-06-12 17:51:19]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=1764" target="_blank"&gt;在服务端合并和压缩JavaScript和CSS文件&lt;/a&gt; [2010-06-11 11:55:52]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=1500" target="_blank"&gt;为什么不压缩 HTML&lt;/a&gt; [2010-05-04 10:23:50]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=1244" target="_blank"&gt;MySQL从压缩文件恢复数据&lt;/a&gt; [2010-03-24 23:34:24]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=1100" target="_blank"&gt;使用Gzip压缩网页&lt;/a&gt; [2010-03-01 13:47:12]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=835" target="_blank"&gt;compress指令并不是总是压缩文件&lt;/a&gt; [2009-12-17 22:13:42]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=824" target="_blank"&gt;php的echo为什么这么慢&lt;/a&gt; [2009-12-16 08:56:47]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=658" target="_blank"&gt;使用系统命令实现文件的压缩与加密&lt;/a&gt; [2009-11-19 22:41:24]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=503" target="_blank"&gt;Linux下常用压缩格式的压缩与解压方法&lt;/a&gt; [2009-11-09 10:52:05]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=348" target="_blank"&gt;apache,php的gzip压缩功能&lt;/a&gt; [2009-10-28 20:48:17]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=333" target="_blank"&gt;mod_gzip：Apache的HTTP压缩优化&lt;/a&gt; [2009-10-27 20:55:31]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=319" target="_blank"&gt;启用memcached压缩注意事项&lt;/a&gt; [2009-10-26 23:12:02]&lt;/li&gt;&lt;/ol&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/WgjnWHyFwr_p8xoJ-xi6dSVS_9c/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/WgjnWHyFwr_p8xoJ-xi6dSVS_9c/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/WgjnWHyFwr_p8xoJ-xi6dSVS_9c/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/WgjnWHyFwr_p8xoJ-xi6dSVS_9c/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/blogreadIT/~4/cIGY110O0Gc" height="1" width="1"/&gt;</description>
		<content><![CDATA[前两天发布那个rsync算法后，想看看数据压缩的算法，知道一个经典的压缩算法Huffman算法。你应该听说过&nbsp;David Huffman&nbsp;和他的经典的压缩算法——&nbsp;Huffman Code，这是一种通过字符出现频率，Priority Queue，和二叉树来进行的一种压缩算法，这种二叉树又叫Huffman二叉树 —— 一种带权重的树。但是网上查了一下，中文社区内好像没有把这个算法说得很清楚的文章，尤其是树的构造，而正好看到一篇国外的文章《A Simple Example of Huffman Code on a String》，其中的例子浅显易懂，相当不错，我就转了过来。注意，我没有对此文完全翻译。]]></content>
	<feedburner:origLink>http://blogread.cn/it/article.php?id=5414</feedburner:origLink></item>
	<item>
		<title>从排队等待谈进度条设计</title>
		<link>http://feedproxy.google.com/~r/blogreadIT/~3/p24vTcM1TkY/article.php</link>
		<author>CDCer</author>
		<pubDate>2012-05-28 13:33:26</pubDate>
		<category domain="http://blogread.cn/it/category.php?id=20">信息和交互</category>
		<guid isPermaLink="false">http://blogread.cn/it/article.php?id=5413</guid>
		<comments>http://blogread.cn/it/article.php?id=5413#comment</comments>
		<description>&lt;p&gt;&lt;strong&gt;标签：&lt;/strong&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://blogread.cn/it/tags.php?tag=%E6%8E%92%E9%98%9F" target="_blank"&gt;排队&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://blogread.cn/it/tags.php?tag=%E8%BF%9B%E5%BA%A6%E6%9D%A1" target="_blank"&gt;进度条&lt;/a&gt;&lt;/p&gt;&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;A href="http://cdc.tencent.com/?p=5625" target=_blank&gt;&lt;IMG src="http://cdc.tencent.com/wp-content/uploads/2012/05/banner11.jpg"&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P align=left&gt;　　排队等待是一种日常中常见的现象，例如新年领开工利是、去排队购买首发的苹果产品、每天中午去食堂排队购买午餐。排队等待在我们的生活中无处不在且看似是一个简单的现象。即使是种简单的存在，但也有其复杂的一面，当存在着很多条队列时，确定每条队列是做什么的就变得困难了；在加入队列后，人们会产生：大概要等多久？为什么队伍很久没有往前移动？等诸多疑问。无法解释的等待是令人烦躁的，不公平的等待则可能引发人们的怒火。&lt;/P&gt;
&lt;P align=left&gt;　　经历过领开工利是的同学应该对于当天排队等待的回忆不会很糟，甚至觉得还不错，是一个值得回忆的经历，明年应该还会去参加。但经历过去火车站购买车票的同学多半会不愿意再去第二次了。不管痛苦还是愉快也好，排队等待有时是不可避免的，那有没有办法可以降低其中的痛苦程度呢？有心理学家曾对如何提升排队等待过程的愉悦感做过研究并提出了一些解决方法。近期正好也做了关于提升管家中进度条体验的优化设计，下面就结合进度条的设计来逐一介绍提升等待体验的设计方法。&lt;/P&gt;
&lt;P align=left&gt;&lt;STRONG&gt;&lt;/STRONG&gt;&amp;nbsp;&lt;/P&gt;
&lt;P align=left&gt;&lt;STRONG&gt;提供清晰的体验概念模型&lt;/STRONG&gt;&lt;/P&gt;
&lt;P align=left&gt;　　概念模型可以使令人迷惑的产品或者设计转变为条理清晰和可以理解的。周围环境的语义符号(新年后上班第一天、曾经领利是的记忆、大屏幕上的排队指引等)可以让我们明白排在腾大楼下长长的队伍是去领新年开工利是的，而不是去食堂买早餐的。&lt;/P&gt;
&lt;P align=left&gt;　　在使用软件的经历中，用户已经非常熟悉点击【扫描】按钮，出现进度条指示，然后等待扫描的结束这一整个过程。所以如下图所示，用户点击【快速扫描】，接着出现等待进度条，这样的操作概念是符合用户记忆，容易理解的，用户不会产生疑惑。&lt;/P&gt;
&lt;P align=left&gt;&lt;IMG class="aligncenter size-full wp-image-5626" alt="" src="http://cdc.tencent.com/wp-content/uploads/2012/05/24.jpg" width=720 height=202&gt;&amp;nbsp;&lt;/P&gt;
&lt;P align=left&gt;&lt;STRONG&gt;&lt;/STRONG&gt;&amp;nbsp;&lt;/P&gt;
&lt;P align=left&gt;&lt;STRONG&gt;等待的过程应有足够的反馈&lt;/STRONG&gt;&lt;/P&gt;
&lt;P align=left&gt;　　忙碌的维护秩序的工作人员、时而往前移动的队伍以及后面不断增多的等待同学等信息都给了我们足够的反馈，说明距离领到利是的目标越来越近了且排队等待是合理的。&lt;/P&gt;
&lt;P align=left&gt;　　想象一下，如果当进度条出现后，所有信息都是静止的：进度条没有移动、没有当前扫描进度的指示、没有变化的数字，这种等待让用户瞬间产生焦虑和不安，他们会疑惑“到底什么时候才会扫描完成？”、“到底电脑是否在正常工作呢？”。在做进度条优化设计时，就大量的提供了变化的信息，给出足够的反馈，让用户明白电脑是正常的，他们的等待是合理的。&lt;/P&gt;
&lt;P align=left&gt;&lt;IMG class="aligncenter size-full wp-image-5628" alt="" src="http://cdc.tencent.com/wp-content/uploads/2012/05/33.jpg" width=565 height=175&gt;&lt;/P&gt;
&lt;P align=left&gt;&amp;nbsp;&lt;/P&gt;
&lt;P align=left&gt;&lt;STRONG&gt;&lt;/STRONG&gt;&amp;nbsp;&lt;/P&gt;
&lt;P align=left&gt;&lt;STRONG&gt;符合或者超越期待&lt;/STRONG&gt;&lt;/P&gt;
&lt;P align=left&gt;　　我们在开始排队等待时常抱以消极的期望值，认为等待会是个漫长的过程。在设计时可以利用这点来作出符合或者超越用户期待的假象，这样可以对提升用户体验有所帮助。&lt;/P&gt;
&lt;P align=left&gt;　　如果从技术上暂时无法提高扫描的效率，我们可以在扫描开始之前让用户有所心理准备，降低他们的期待。例如在扫描前可以通过弹框的方式提醒用户：扫描过程较为漫长，请您耐心等待。这样到最终扫描结束，用户可能会发觉其实扫描并不是那么的漫长，这也就变相的超越了用户的期待。&lt;/P&gt;
&lt;P align=left&gt;&lt;IMG alt="" src="http://cdc.tencent.com/wp-content/uploads/2012/05/43.jpg" width=380 height=160&gt;&lt;/P&gt;
&lt;P align=center&gt;&amp;nbsp;&lt;/P&gt;
&lt;P align=left&gt;&lt;STRONG&gt;分散用户的注意力&lt;/STRONG&gt;&lt;/P&gt;
&lt;P align=left&gt;　　一个有很多事情发生的时间段会显得比在一个相同时间但没有任何事发生的时间段快得多。“度日如年”就是这个道理。经典的在电梯口放置镜子的故事就是利用分散用户注意力的方法来提升用户等待的体验。&lt;/P&gt;
&lt;P align=left&gt;　　很多游戏的加载都采用了这种方法来提高用户等待的体验，比如七雄争霸在加载的过程中会出现“打地鼠”小游戏，将用户的注意力吸引到小游戏上，从而不会关注加载等待的事情。某款安全软件也采用了这种方法，当用户进入较长的扫描等待时，界面上会弹出气泡提示用户可以进入皮肤中心换换界面的皮肤玩一玩。从这点出发，管家也可以善以利用，如果管家有什么新的功能推出，可以采用这种形式向用户推介，即提高了等待的体验也起到了功能宣传的作用。&lt;/P&gt;
&lt;P align=left&gt;&lt;STRONG&gt;公平&lt;/STRONG&gt;&lt;/P&gt;
&lt;P align=left&gt;　　我们反感插队的人，对不公平的现象会产生愤怒。有心理学试验表明即使所有的队列都以平均速度来移动，不管人们在哪个队伍里，他们都感觉自己那队是移动得最慢的。这也是为什么最好的队列设计是只采用一条队列，这样人们会认为自己得到了公平的对待。&lt;/P&gt;
&lt;P align=left&gt;　　回到进度条的设计，我们即使用再多的设计方法，其实也只是稍微减缓了用户在等待感觉上的慢。我们从根本上还是要提高产品自身的扫描效率和性能，让使用我们产品的用户受到的待遇是与使用其他类似产品用户所受待遇是同等的，最好是超越的。用户没有道理去忍受一款性能低下的产品带给他们的等待痛苦，这也就是让用户感受到公平是最基本的。&lt;/P&gt;
&lt;P align=left&gt;&lt;STRONG&gt;积极的开始，美好的结尾&lt;/STRONG&gt;&lt;/P&gt;
&lt;P align=left&gt;　　一个漫长的活动过程，在记忆中的感受重要程度排序为：结尾，开始，中间过程。其中结尾的感受对整个活动过程体验的影响是最大的，如果能在结尾时增加稍许愉快的成分，即使整体过程是不愉快的，用户仍然会对整个过程产生愉快的感受。&lt;/P&gt;
&lt;P align=left&gt;　　进度条设计上也同样在开始与结尾处做了优化。在扫描刚开始，我们对进度条做了假移动的处理，进度条一开始会比较快的移动起来，其实移动的这段距离与实际的扫描比率是没有关系的。比如，有100个文件需要扫描，进度条每移动1%的距离代表扫描了一个文件。假移动就是让进度条一开始快速的移动10%的距离，其实在后台并没有扫描10个文件，可能只是扫描了1个文件。这样的做法会给用户一个积极的起步感，用户看到已经开始扫描了可能就会去做其他事情。&lt;/P&gt;
&lt;P align=left&gt;　　美好的结尾通常在人的记忆中会占有很重要的影响力。在管家中，当扫描结束后会跳转到结果页面，在这个页面上会展现此次扫描的详细结果并且给予很强的成就感，比如没有发现病毒会用显眼的绿色对号，肯定的文本让用户确信自己的电脑是安全的。如果扫描出病毒或电脑问题，界面上会给用户明确的清除按钮和其他特殊情况处理途径，让用户能很方便的解决问题并使电脑恢复正常。当用户解决完所有问题后，会给出解决成功的成就感提示。&lt;/P&gt;
&lt;P align=left&gt;　　生活中需求大于资源是常态，我们必须面对各种的排队等待。电脑的性能瓶颈也是暂时无法解决的，希望本文能对大家的设计工作有所帮助，让等待不再那么无奈。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(本文出自腾讯CDC博客: &lt;A href="http://cdc.tencent.com/?p=5625" target=_blank&gt;http://cdc.tencent.com/?p=5625&lt;/A&gt;)&lt;/P&gt;
				&lt;p&gt;&lt;strong&gt;您可能还对下面的文章感兴趣：&lt;/strong&gt;&lt;/p&gt;
				&lt;p&gt;&lt;ol&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=1651" target="_blank"&gt;PHP上传进度条深度解析&lt;/a&gt; [2010-05-27 12:34:41]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=1435" target="_blank"&gt;PHP上传进度条深度解析&lt;/a&gt; [2010-04-22 22:56:07]&lt;/li&gt;&lt;/ol&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/FYTZSdXudzQCt8bR2J78mksUh2s/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/FYTZSdXudzQCt8bR2J78mksUh2s/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/FYTZSdXudzQCt8bR2J78mksUh2s/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/FYTZSdXudzQCt8bR2J78mksUh2s/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/blogreadIT/~4/p24vTcM1TkY" height="1" width="1"/&gt;</description>
		<content><![CDATA[　　排队等待是一种日常中常见的现象，例如新年领开工利是、去排队购买首发的苹果产品、每天中午去食堂排队购买午餐。排队等待在我们的生活中无处不在且看似是一个简单的现象。即使是种简单的存在，但也有其复杂的一面，当存在着很多条队列时，确定每条队列是做什么的就变得困难了；在加入队列后，人们会产生：大概要等多久？为什么队伍很久没有往前移动？等诸多疑问。无法解释的等待是令人烦躁的，不公平的等待则可能引发人们的怒火。 　　经历过领开工利是的同学应该对于当天排队等待的回忆不会很糟，甚至觉得还不错，是一个值得回忆的经历，明年应该还会去参加。但经历过去火车站购买车票的同学多半会不愿意再去第二次了。不管痛苦还是愉快也好，排队等待有时是不可避免的，那有没有办法可以降低其中的痛苦程度呢？有心理学家曾对如何提升排队等待过程的愉悦感做过研究并提出了一些解决方法。]]></content>
	<feedburner:origLink>http://blogread.cn/it/article.php?id=5413</feedburner:origLink></item>
	<item>
		<title>MariaDB与Percona XtraDB的Group Commit实现原理分析</title>
		<link>http://feedproxy.google.com/~r/blogreadIT/~3/dXVo2g5Nxsk/article.php</link>
		<author>MySQLOPS 数据库与运维自动化技术分享</author>
		<pubDate>2012-05-28 13:32:30</pubDate>
		<category domain="http://blogread.cn/it/category.php?id=3">MySQL</category>
		<guid isPermaLink="false">http://blogread.cn/it/article.php?id=5412</guid>
		<comments>http://blogread.cn/it/article.php?id=5412#comment</comments>
		<description>&lt;p&gt;&lt;strong&gt;标签：&lt;/strong&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://blogread.cn/it/tags.php?tag=MariaDB" target="_blank"&gt;MariaDB&lt;/a&gt;&lt;/p&gt;&lt;P&gt;MySQL数据库InnoDB存储引擎一直有一个Bug，就是当开启binlog时，无法进行group commit。究其原因，是为了保证InnoDB存储引擎的事务日志与mysqlbinlog日志的顺序一致性。&lt;/P&gt;
&lt;P&gt;在prepare前需要获取mutex，直到commit完成之后释放，这也禁用了group commit的功能。&lt;/P&gt;
&lt;P&gt;对于MySQL数据库InnoDB存储引擎 group commit的分析，可参考系列文章：&lt;A href="http://www.mysqlops.com/2012/05/23/mysql-innodb-group-commit-1.html"&gt;&lt;FONT color=#0066cc&gt;MySQL/InnoDB和Group Commit(1)&lt;/FONT&gt;&lt;/A&gt;；&lt;A href="http://www.mysqlops.com/2012/05/23/mysql-innodb-group-commit.html"&gt;&lt;FONT color=#0066cc&gt;MySQLl/InnoDB和Group Commit(2)&lt;/FONT&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;对于MariaDB / PerconaXtraDB如何实现Group commit，可参考MariaDB官方网站的3篇WorkLog：&lt;SPAN id=more-5758&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;
&lt;DIV&gt;WL#116:&lt;A href="http://askmonty.org/worklog/Server-Sprint/?tid=116"&gt;&lt;FONT color=#0066cc&gt; Efficient group commit for binary log&lt;/FONT&gt;&lt;/A&gt;&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV&gt;WL#132: &lt;A href="http://askmonty.org/worklog/Server-Sprint/?tid=132"&gt;&lt;FONT color=#0066cc&gt;Transaction coordinator plugin&lt;/FONT&gt;&lt;/A&gt;&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV&gt;WL#164: &lt;A href="http://askmonty.org/worklog/Server-RawIdeaBin/?tid=164"&gt;&lt;FONT color=#0066cc&gt;Extend crash recovery to recover non-prepared transactions from binlog&lt;/FONT&gt;&lt;/A&gt;&lt;/DIV&gt;&lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;&lt;FONT color=#0066cc&gt;&lt;/FONT&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Percona 5.5.19-rel24代码分析：&lt;/P&gt;
&lt;P&gt;以下分析Group Commit的具体实现，基于Percona 5.5.19-rel24。&lt;/P&gt;
&lt;P&gt;以下提到的功能，在WorkLog WL#116中都有提及。建议先看WL#116，然后有针对性的看下面的函数实现，绝对事半功倍。&lt;/P&gt;
&lt;P&gt;prepare_ordered功能：&lt;/P&gt;
&lt;P&gt;Log.cc::MYSQL_BIN_LOG::write_transaction_to_binlog_events(group_commit_entry *entry)&lt;/P&gt;
&lt;P&gt;mysql_mutex_tLOCK_group_commit_queue;&lt;/P&gt;
&lt;P&gt;事务由mutex保护，加入queue，第一个加入queue的事务负责余下操作；其余事务进入等待。&lt;/P&gt;
&lt;DIV&gt;
&lt;DIV id=highlighter_171720 class="syntaxhighlighter notranslate cpp ie"&gt;
&lt;DIV class=toolbar&gt;&lt;SPAN&gt;
&lt;TABLE border=0 cellSpacing=0 cellPadding=0&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD class=code&gt;
&lt;DIV class=container&gt;
&lt;DIV class="line number1 index0 alt2"&gt;&lt;CODE class="cpp keyword bold"&gt;if&lt;/CODE&gt; &lt;CODE class="cpp plain"&gt;(orig_queue != NULL) &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number2 index1 alt1"&gt;&lt;CODE class="cpp plain"&gt;entry-&amp;gt;thd-&amp;gt;wait_for_wakeup_ready(); &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number3 index2 alt2"&gt;&lt;CODE class="cpp keyword bold"&gt;else&lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number4 index3 alt1"&gt;&lt;CODE class="cpp plain"&gt;trx_group_commit_leader(entry); &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number5 index4 alt2"&gt;&lt;CODE class="cpp plain"&gt;commit_ordered功能： &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number6 index5 alt1"&gt;&lt;CODE class="cpp plain"&gt;ha_innodb.cc::innobase_init -&amp;gt;innobase_hton-&amp;gt;commit_ordered = innobase_commit_ordered&lt;/CODE&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/SPAN&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/DIV&gt;
&lt;P&gt;XA事务总流程：&lt;/P&gt;
&lt;DIV&gt;
&lt;DIV id=highlighter_453029 class="syntaxhighlighter notranslate cpp ie"&gt;
&lt;DIV class=toolbar&gt;&lt;SPAN&gt;
&lt;TABLE border=0 cellSpacing=0 cellPadding=0&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD class=code&gt;
&lt;DIV class=container&gt;
&lt;DIV class="line number1 index0 alt2"&gt;&lt;CODE class="cpp plain"&gt;handler.cc::ha_commit_trans()函数分析 &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number2 index1 alt1"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/CODE&gt;&lt;CODE class="cpp keyword bold"&gt;for&lt;/CODE&gt; &lt;CODE class="cpp plain"&gt;(Ha_trx_info *hi = ha_info; hi; hi = hi-&amp;gt;next()) &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number3 index2 alt2"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/CODE&gt;&lt;CODE class="cpp plain"&gt;handlerton *ht = hi-&amp;gt;ht(); &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number4 index3 alt1"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&lt;/CODE&gt;&amp;nbsp;&lt;/DIV&gt;
&lt;DIV class="line number5 index4 alt2"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/CODE&gt;&lt;CODE class="cpp comments"&gt;// XA事务第一阶段，group fsync prepare日志 &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number6 index5 alt1"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/CODE&gt;&lt;CODE class="cpp comments"&gt;// 其中，binlog的prepare方法为空实现 &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number7 index6 alt2"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/CODE&gt;&lt;CODE class="cpp plain"&gt;err = ht-&amp;gt;prepare(); &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number8 index7 alt1"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/CODE&gt;&lt;CODE class="cpp plain"&gt;need_commit_ordered |= (ht-&amp;gt;commit_ordered != NULL); &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number9 index8 alt2"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&lt;/CODE&gt;&amp;nbsp;&lt;/DIV&gt;
&lt;DIV class="line number10 index9 alt1"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/CODE&gt;&lt;CODE class="cpp comments"&gt;// Binlog group commit，然后调用commit_ordered进行排序 &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number11 index10 alt2"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/CODE&gt;&lt;CODE class="cpp plain"&gt;cookie = tc_log-&amp;gt;log_and_order(); &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number12 index11 alt1"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/CODE&gt;&lt;CODE class="cpp comments"&gt;// XA事务第二阶段，fsync commit日志 &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number13 index12 alt2"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/CODE&gt;&lt;CODE class="cpp plain"&gt;error = commit_one_phase_low(); &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number14 index13 alt1"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&lt;/CODE&gt;&amp;nbsp;&lt;/DIV&gt;
&lt;DIV class="line number15 index14 alt2"&gt;&lt;CODE class="cpp plain"&gt;TC_LOG_BINLOG::log_and_order()函数分析 &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number16 index15 alt1"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/CODE&gt;&lt;CODE class="cpp plain"&gt;binlog_commit_flush_stmt/trx_cache(); &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number17 index16 alt2"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/CODE&gt;&lt;CODE class="cpp plain"&gt;binlog_flush_cache(); &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number18 index17 alt1"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/CODE&gt;&lt;CODE class="cpp plain"&gt;write_transaction_to_binlog(); &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number19 index18 alt2"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&lt;/CODE&gt;&amp;nbsp;&lt;/DIV&gt;
&lt;DIV class="line number20 index19 alt1"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/CODE&gt;&lt;CODE class="cpp comments"&gt;// 事务首先进入binlog group commit queue &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number21 index20 alt2"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/CODE&gt;&lt;CODE class="cpp comments"&gt;// 第一个进入的事务进行binlog group commit &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number22 index21 alt1"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/CODE&gt;&lt;CODE class="cpp comments"&gt;// 其余事务进入等待 &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number23 index22 alt2"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&lt;/CODE&gt;&amp;nbsp;&lt;/DIV&gt;
&lt;DIV class="line number24 index23 alt1"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/CODE&gt;&lt;CODE class="cpp plain"&gt;write_transaction_to_binlog_events(); &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number25 index24 alt2"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/CODE&gt;&lt;CODE class="cpp plain"&gt;trx_group_commit_leader(); (entry-&amp;gt;thd-&amp;gt;wait_for_wakeup_ready()) &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number26 index25 alt1"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&lt;/CODE&gt;&amp;nbsp;&lt;/DIV&gt;
&lt;DIV class="line number27 index26 alt2"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/CODE&gt;&lt;CODE class="cpp plain"&gt;… &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number28 index27 alt1"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&lt;/CODE&gt;&amp;nbsp;&lt;/DIV&gt;
&lt;DIV class="line number29 index28 alt2"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/CODE&gt;&lt;CODE class="cpp comments"&gt;// binlog完成fsync之后，调用此函数对事物进行排序 &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number30 index29 alt1"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/CODE&gt;&lt;CODE class="cpp comments"&gt;// 排序前，需要获取LOCK_commit_orderedmutex &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number31 index30 alt2"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&lt;/CODE&gt;&amp;nbsp;&lt;/DIV&gt;
&lt;DIV class="line number32 index31 alt1"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/CODE&gt;&lt;CODE class="cpp plain"&gt;run_commit_ordered(); &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number33 index32 alt2"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/CODE&gt;&lt;CODE class="cpp keyword bold"&gt;for&lt;/CODE&gt; &lt;CODE class="cpp plain"&gt;( … ) &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number34 index33 alt1"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/CODE&gt;&lt;CODE class="cpp plain"&gt;ht-&amp;gt;commit_ordered(); &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number35 index34 alt2"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/CODE&gt;&lt;CODE class="cpp comments"&gt;// InnoDB提供了此函数，实现排序功能 &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number36 index35 alt1"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/CODE&gt;&lt;CODE class="cpp plain"&gt;innobase_commit_ordered(); &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number37 index36 alt2"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&lt;/CODE&gt;&amp;nbsp;&lt;/DIV&gt;
&lt;DIV class="line number38 index37 alt1"&gt;&lt;CODE class="cpp plain"&gt;Log.cc::MYSQL_BIN_LOG::trx_group_commit_leader()函数分析 &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number39 index38 alt2"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&lt;/CODE&gt;&amp;nbsp;&lt;/DIV&gt;
&lt;DIV class="line number40 index39 alt1"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/CODE&gt;&lt;CODE class="cpp comments"&gt;// 获取当前queue，并且重新开启一个queue &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number41 index40 alt2"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/CODE&gt;&lt;CODE class="cpp comments"&gt;// 本queue中的binlog，都由当前事务group commit &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number42 index41 alt1"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&lt;/CODE&gt;&amp;nbsp;&lt;/DIV&gt;
&lt;DIV class="line number43 index42 alt2"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/CODE&gt;&lt;CODE class="cpp comments"&gt;// 新queue中的binlog，由新queue中的第一个事务等待LOCK_logmutex &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number44 index43 alt1"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/CODE&gt;&lt;CODE class="cpp plain"&gt;mysql_mutex_lock(&amp;amp;LOCK_log); &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number45 index44 alt2"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/CODE&gt;&lt;CODE class="cpp plain"&gt;mysql_mutex_lock(&amp;amp;LOCK_group_commit_queue); &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number46 index45 alt1"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/CODE&gt;&lt;CODE class="cpp plain"&gt;current = group_commit_queue; &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number47 index46 alt2"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/CODE&gt;&lt;CODE class="cpp plain"&gt;group_commit_queue = NULL; &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number48 index47 alt1"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/CODE&gt;&lt;CODE class="cpp plain"&gt;mysql_mutex_unlock(&amp;amp;LOCK_group_commit_queue); &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number49 index48 alt2"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&lt;/CODE&gt;&amp;nbsp;&lt;/DIV&gt;
&lt;DIV class="line number50 index49 alt1"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/CODE&gt;&lt;CODE class="cpp comments"&gt;// 写binlog，最后执行一次fsync操作 &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number51 index50 alt2"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&lt;/CODE&gt;&amp;nbsp;&lt;/DIV&gt;
&lt;DIV class="line number52 index51 alt1"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/CODE&gt;&lt;CODE class="cpp keyword bold"&gt;for&lt;/CODE&gt; &lt;CODE class="cpp plain"&gt;( … ) &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number53 index52 alt2"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/CODE&gt;&lt;CODE class="cpp plain"&gt;write_transaction(); &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number54 index53 alt1"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/CODE&gt;&lt;CODE class="cpp plain"&gt;flush_and_sync(); &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number55 index54 alt2"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&lt;/CODE&gt;&amp;nbsp;&lt;/DIV&gt;
&lt;DIV class="line number56 index55 alt1"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/CODE&gt;&lt;CODE class="cpp comments"&gt;// 获取commit_orderedmutex，然后才能释放LOCK_logmutex &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number57 index56 alt2"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/CODE&gt;&lt;CODE class="cpp comments"&gt;// 保证下一个queue，不会在当前queue之前调用commit_ordered &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number58 index57 alt1"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&lt;/CODE&gt;&amp;nbsp;&lt;/DIV&gt;
&lt;DIV class="line number59 index58 alt2"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/CODE&gt;&lt;CODE class="cpp plain"&gt;mysql_mutex_lock(&amp;amp;LOCK_commit_ordered); &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number60 index59 alt1"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/CODE&gt;&lt;CODE class="cpp plain"&gt;mysql_mutex_unlock(&amp;amp;LOCK_log); &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number61 index60 alt2"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&lt;/CODE&gt;&amp;nbsp;&lt;/DIV&gt;
&lt;DIV class="line number62 index61 alt1"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/CODE&gt;&lt;CODE class="cpp comments"&gt;// 按照prepare的顺序，调用引擎提供的commit_ordered方法 &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number63 index62 alt2"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/CODE&gt;&lt;CODE class="cpp comments"&gt;// 由于是按序逐个执行commit_ordered方法，因此能够保证事务 &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number64 index63 alt1"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/CODE&gt;&lt;CODE class="cpp comments"&gt;// commit的顺序与binlog commit的顺序是完全一致的 &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number65 index64 alt2"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/CODE&gt;&lt;CODE class="cpp comments"&gt;// 在commit_ordered方法调用完成之后，才能唤醒对应的线程 &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number66 index65 alt1"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/CODE&gt;&lt;CODE class="cpp comments"&gt;// 事务线程被唤醒之后，才能够进入2PC的第二阶段 &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number67 index66 alt2"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/CODE&gt;&lt;CODE class="cpp comments"&gt;// 返回handler.cc::ha_commit_trans()函数，执行commit_one_phase_low &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number68 index67 alt1"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&lt;/CODE&gt;&amp;nbsp;&lt;/DIV&gt;
&lt;DIV class="line number69 index68 alt2"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/CODE&gt;&lt;CODE class="cpp plain"&gt;current = queue; &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number70 index69 alt1"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/CODE&gt;&lt;CODE class="cpp keyword bold"&gt;while&lt;/CODE&gt; &lt;CODE class="cpp plain"&gt;(current != NULL) &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number71 index70 alt2"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/CODE&gt;&lt;CODE class="cpp plain"&gt;run_commit_ordered(current-&amp;gt;thd, current-&amp;gt;all); &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number72 index71 alt1"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/CODE&gt;&lt;CODE class="cpp keyword bold"&gt;if&lt;/CODE&gt; &lt;CODE class="cpp plain"&gt;(ht-&amp;gt;commit_ordered) &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number73 index72 alt2"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/CODE&gt;&lt;CODE class="cpp plain"&gt;ht-&amp;gt;commit_ordered(ht, thd, all); &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number74 index73 alt1"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/CODE&gt;&lt;CODE class="cpp plain"&gt;current-&amp;gt;thd-&amp;gt;signal_wakeup_ready(); &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number75 index74 alt2"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/CODE&gt;&lt;CODE class="cpp plain"&gt;current = next; &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number76 index75 alt1"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&lt;/CODE&gt;&amp;nbsp;&lt;/DIV&gt;
&lt;DIV class="line number77 index76 alt2"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/CODE&gt;&lt;CODE class="cpp comments"&gt;// 最后释放commit ordered mutex &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number78 index77 alt1"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&lt;/CODE&gt;&amp;nbsp;&lt;/DIV&gt;
&lt;DIV class="line number79 index78 alt2"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/CODE&gt;&lt;CODE class="cpp plain"&gt;mysql_mutex_unlock(&amp;amp;LOCK_commit_ordered); &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number80 index79 alt1"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&lt;/CODE&gt;&amp;nbsp;&lt;/DIV&gt;
&lt;DIV class="line number81 index80 alt2"&gt;&lt;CODE class="cpp plain"&gt;ha_innodb.cc::innobase_commit_ordered -&amp;gt;innobase_commit_ordered_low函数分析 &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number82 index81 alt1"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/CODE&gt;&lt;CODE class="cpp comments"&gt;// 获取事务对应的binlog日志的位置 &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number83 index82 alt2"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/CODE&gt;&lt;CODE class="cpp plain"&gt;mysql_bin_log_commit_pos(); &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number84 index83 alt1"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/CODE&gt;&lt;CODE class="cpp comments"&gt;// 设置当前事务标识为flush log later，写commit日志，但是不flush &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number85 index84 alt2"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/CODE&gt;&lt;CODE class="cpp plain"&gt;trx-&amp;gt;flush_log_later = TRUE; &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number86 index85 alt1"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/CODE&gt;&lt;CODE class="cpp plain"&gt;innobase_commit_low(trx); &lt;/CODE&gt;&lt;/DIV&gt;
&lt;DIV class="line number87 index86 alt2"&gt;&lt;CODE class="cpp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/CODE&gt;&lt;CODE class="cpp plain"&gt;trx-&amp;gt;flush_log_later = FALSE;&lt;/CODE&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/SPAN&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/DIV&gt;
&lt;P&gt;在函数ha_innodb.cc::innobase_commit_ordered执行完成之后，逐层返回到handler.cc::ha_commit_trans()函数，执行2PC的第二阶段，commit_one_phase_low()，对Commit日志进行group commit。&lt;/P&gt;
&lt;P&gt;WL#132&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;
&lt;DIV&gt;二进制日志Binlog在MySQL数据库中起着TC(Transaction Coordinator)功能二进制日志(Binlog只是TC的一种方案，另一种是Mmap TC)；&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV&gt;TC在crash恢复时作为控制中心，决定各引擎参与事务的提交与回滚(在WL#164之前，binlog只能与innodb-flush-log-at-trx-commit = 1设置同时使用，二进制日志binlog中的事务一定commit；不存在与binlog中的事务一定rollback；不存在re-play binlog的操作)；&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV&gt;MySQL数据库为TC做了所谓“middle engine”XA优化(在参与XA事务的所有参与者中，有且仅有一个参与者可以将【prepare，commit】组合简化为commit即可，但是前提是此参与者的commit要在其他参与者完成prepare，未进行commit操作时进行，middle engine)，Binlog不需要prepare阶段，其他引擎prepare之后直接写binlog即可；&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV&gt;二进制日志Binlog新增log_and_order方法，控制事务提交顺序；目前，InnoDB存储引擎实现了commit_ordered方法，未实现prepare_ordered方法。&lt;/DIV&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;WL#164&lt;/P&gt;
&lt;P&gt;在Group Commit的基础上，MariaDB数据库再接再厉，推出WL#164。将一次事务提交需要的3次fsync，降低为1次- binlog fsync。用户可以在将参数innodb-flush-log-at-trx-commit设置为{0,2}时，达到与该参数为1时同样的可靠性，不会丢失已提交更新。实现方案也较为简洁，在原有XA recover的基础上，新增了一个处理【二进制日志binlog存在，但是InnoDB prepare log不存在】的情况，此时需要根据binlog重做(re-play)一遍即可(类似于slave根据binlog恢复的情形)。&lt;/P&gt;
&lt;P&gt;在WL#164之后，binlog与InnoDB redo log之间的关系，存在以下几种组合：&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;
&lt;DIV&gt;Binlog与commit log同时存在 ——》no operation in crash recovery&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV&gt;Binlog与prepare log同时存在 ——》commit&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV&gt;Binlog存在，prepare log不存在 ——》re-play binlog&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV&gt;Binlog不存在，prepare log存在 ——》rollback&lt;/DIV&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;MySQL数据库外部XA事务支持，语法见上面的博客。&lt;/P&gt;
&lt;P&gt;经过测试，&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;
&lt;DIV&gt;在调用xa prepare命令时，同样不写binlog，或者说是binlog的prepare为空。但是会写InnoDB存储引擎的prepare log。&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV&gt;在调用xa commit命令时，会写binlog，同时写InnoDB存储引擎的commit log。&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV&gt;问题？二进制日志binlog不写prepare日志，如何恢复？&lt;/DIV&gt;&lt;/LI&gt;&lt;/UL&gt;
				&lt;p&gt;&lt;strong&gt;您可能还对下面的文章感兴趣：&lt;/strong&gt;&lt;/p&gt;
				&lt;p&gt;很抱歉，暂时没有...... &lt;/p&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/jvni4qCW9nnw7WJel6yPP8XQ_nA/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/jvni4qCW9nnw7WJel6yPP8XQ_nA/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/jvni4qCW9nnw7WJel6yPP8XQ_nA/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/jvni4qCW9nnw7WJel6yPP8XQ_nA/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/blogreadIT/~4/dXVo2g5Nxsk" height="1" width="1"/&gt;</description>
		<content><![CDATA[MySQL数据库InnoDB存储引擎一直有一个Bug，就是当开启binlog时，无法进行group commit。究其原因，是为了保证InnoDB存储引擎的事务日志与mysqlbinlog日志的顺序一致性。 在prepare前需要获取mutex，直到commit完成之后释放，这也禁用了group commit的功能。 ]]></content>
	<feedburner:origLink>http://blogread.cn/it/article.php?id=5412</feedburner:origLink></item>
	<item>
		<title>全表扫描却产生大量db file sequential read一例</title>
		<link>http://feedproxy.google.com/~r/blogreadIT/~3/JNB9cvBvE5o/article.php</link>
		<author>老熊</author>
		<pubDate>2012-05-28 13:30:22</pubDate>
		<category domain="http://blogread.cn/it/category.php?id=4">Oracle</category>
		<guid isPermaLink="false">http://blogread.cn/it/article.php?id=5411</guid>
		<comments>http://blogread.cn/it/article.php?id=5411#comment</comments>
		<description>&lt;p&gt;&lt;strong&gt;标签：&lt;/strong&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://blogread.cn/it/tags.php?tag=OLTP" target="_blank"&gt;OLTP&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://blogread.cn/it/tags.php?tag=sequential" target="_blank"&gt;sequential&lt;/a&gt;&lt;/p&gt;&lt;P&gt;开发人员在进行新系统上线前的数据校验测试时，发现一条手工执行的SQL执行了超过1小时还没有返回结果。SQL很简单：&lt;/P&gt;
&lt;DIV class=dp-highlighter&gt;
&lt;DIV class=bar&gt;&lt;PRE style="DISPLAY: none" class=sql name="code"&gt;SELECT *
  FROM MOBILE_call_1204_OLD
 WHERE BILLING_NBR = '189xxxxxxxx'
   AND START_DATE = TO_DATE('2012-4-9 21:55:42', 'yyyy-mm-dd hh24:mi:ss')
&lt;/PRE&gt;&lt;/DIV&gt;&lt;/DIV&gt;
&lt;P&gt;下面是这条SQL的真实的执行计划：&lt;/P&gt;
&lt;DIV class=dp-highlighter&gt;
&lt;DIV class=bar&gt;&lt;PRE style="DISPLAY: none" class=sql name="code"&gt;-------------------------------------------------------------
| Id   | Operation          | Name                 | E-Rows |
-------------------------------------------------------------
|    0 | SELECT STATEMENT   |                      |        |
| *  1 |  TABLE ACCESS FULL | MOBILE_CALL_1204_OLD |      1 |
-------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(("START_DATE"=TO_DATE(' 2012-04-09 21:55:42', 'syyyy-mm-dd hh24:mi:ss') AND "BILLING_NBR"='189xxxxxxxx'))
&lt;/PRE&gt;&lt;/DIV&gt;&lt;/DIV&gt;
&lt;P&gt;很显然，在这个表上建billing_nbr和start_date的复合索引，这条SQL就能很快执行完（实际上最后也建了索引）。但是这里我们要探讨的是，为什么这么一条简单的SQL语句，执行了超过1小时还没有结果。MOBILE_CALL_1204_OLD这张表的大小约为12GB，以系统的IO能力，正常情况下不会执行这么长的时间。简单地看了一下，系统的CPU以及IO压力都不高。假设单进程全表扫描表，每秒扫描50MB大小（这实际上是一个很保守的扫描速度了），那么只需要245秒就可以完成扫描。&lt;/P&gt;
&lt;P&gt;下面来诊断一下SQL为什么会这么不正常地慢。看看会话的等待（以下会用到Oracle大牛&lt;A href="http://blog.tanelpoder.com/" target=_blank&gt;&lt;FONT color=#0066cc&gt;Tanel Poder&lt;/FONT&gt;&lt;/A&gt;的脚本）：&lt;/P&gt;
&lt;DIV class=dp-highlighter&gt;
&lt;DIV class=bar&gt;&lt;PRE style="DISPLAY: none" class=sql name="code"&gt;SQL&amp;gt; @waitprof print 4038 e 1000000
                                                                  Distinct   Avg time
    SID STATE   EVENT                         Time      Time ms     Events   ms/Event
------- ------- -------------------------  ------- ------------ ---------- ----------
   4038 WAITING db file sequential read      99.61     4482.450        272     16.480
   4038 WORKING On CPU / runqueue              .39       17.550        271       .065
&lt;/PRE&gt;&lt;/DIV&gt;&lt;/DIV&gt;
&lt;P&gt;明明是全表扫描的SQL，为什么99%以上的等待时间是db file sequential read，即单块读？！多执行几次waitprof脚本，得到的结果是一致的（注意这里的数据，特别是平均等待时间并不一定是准确的值，这里重点关注的是等待时间的分布）。&lt;/P&gt;
&lt;P&gt;那么SQL执行计划为全表扫描（或索引快速全扫描）的时候，在运行时会有哪些情况实际上是单块读？我目前能想到的有：&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;db_file_multiblock_read_count参数设置为1 
&lt;LI&gt;表或索引的大部分块在buffer cache中，少量不连续的块在磁盘上。 
&lt;LI&gt;一些特殊的块，比如段头 
&lt;LI&gt;行链接的块 
&lt;LI&gt;LOB列的索引块和cache的LOB块（虽然10046事件看不到lob索引和cache的lob的读等待，但客观上是存在的。） &lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;那么在这条SQL语句产生的大量单块读，又是属于什么情况呢？我们来看看单块读更细节的情况：&lt;/P&gt;
&lt;DIV class=dp-highlighter&gt;
&lt;DIV class=bar&gt;&lt;PRE style="DISPLAY: none" class=sql name="code"&gt;SQL&amp;gt; @waitprof print 4038 e1 200000

                                                    % Total  Total Event   Distinct   Avg time
    SID STATE   EVENT                    P1            Time      Time ms     Events   ms/Event
------- ------- ------------------------ ------------------ ------------ ---------- ----------
   4038 WAITING db file sequential read  file#= 353   30.63      581.923        35     16.626
   4038 WAITING db file sequential read  file#= 355   28.14      534.641        40     13.366
   4038 WAITING db file sequential read  file#= 354   20.52      389.909        24     16.246
   4038 WAITING db file sequential read  file#= 3     19.63      372.942        35     10.655
   4038 WORKING On CPU / runqueue                       .66       12.616       133       .095
   4038 WAITING db file sequential read  file#= 293     .42        7.971         1      7.971
&lt;/PRE&gt;&lt;/DIV&gt;&lt;/DIV&gt;
&lt;P&gt;多次执行同样的SQL，发现绝大部分的单块读发生在3、353-355这四个文件上，我们来看看这4个文件是什么：&lt;/P&gt;
&lt;DIV class=dp-highlighter&gt;
&lt;DIV class=bar&gt;&lt;PRE style="DISPLAY: none" class=sql name="code"&gt;SQL&amp;gt; select file_id,tablespace_name from dba_data_files where file_id in (355,3,353,354);

   FILE_ID TABLESPACE_NAME
---------- ------------------------------
         3 UNDOTBS1
       353 UNDOTBS1
       354 UNDOTBS1
       355 UNDOTBS1
&lt;/PRE&gt;&lt;/DIV&gt;&lt;/DIV&gt;
&lt;P&gt;&lt;STRONG&gt;原来是UNDO表空间&lt;/STRONG&gt;。那么另一个疑问就会来了，为什么在UNDO上产生了如此之多的单块读？首先要肯定的是，这条简单的查询语句，是进行的一致性读。那么在进行一致性读的过程中，会有两个动作会涉及到读UNDO块，延迟块清除和构建CR块。下面我们用另一个脚本来查看会话当时的状况：&lt;/P&gt;
&lt;DIV class=dp-highlighter&gt;
&lt;DIV class=bar&gt;&lt;PRE style="DISPLAY: none" class=sql name="code"&gt;SQL&amp;gt; @snapper all,out 5 3 4038
Sampling SID 4038 with interval 5 seconds, taking 3 snapshots...
setting stats to all due option = all

-- Session Snapper v3.52 by Tanel Poder @ E2SN ( http://tech.e2sn.com )

-------------------------------------------------------------------------------------------------------------------------------------
    SID, USERNAME  , TYPE, STATISTIC                                                 ,     HDELTA, HDELTA/SEC,    %TIME, GRAPH
-------------------------------------------------------------------------------------------------------------------------------------
   4038, BILL_MY   , STAT, session logical reads                                     ,        488,       97.6,
   4038, BILL_MY   , STAT, user I/O wait time                                        ,        429,       85.8,
   4038, BILL_MY   , STAT, non - idle wait time                                      ,        429,       85.8,
   4038, BILL_MY   , STAT, non - idle wait count                                     ,        377,       75.4,
   4038, BILL_MY   , STAT, physical read total IO requests                           ,        377,       75.4,
   4038, BILL_MY   , STAT, physical read total bytes                                 ,      3.13M,    625.87k,
   4038, BILL_MY   , STAT, cell physical IO interconnect bytes                       ,      3.13M,    625.87k,
   4038, BILL_MY   , STAT, consistent gets                                           ,        488,       97.6,
   4038, BILL_MY   , STAT, consistent gets from cache                                ,        488,       97.6,
   4038, BILL_MY   , STAT, consistent gets from cache (fastpath)                     ,          8,        1.6,
   4038, BILL_MY   , STAT, consistent gets - examination                             ,        478,       95.6,
   4038, BILL_MY   , STAT, logical read bytes from cache                             ,         4M,    799.54k,
   4038, BILL_MY   , STAT, physical reads                                            ,        382,       76.4
   4038, BILL_MY   , STAT, physical reads cache                                      ,        382,       76.4,
   4038, BILL_MY   , STAT, physical read IO requests                                 ,        377,       75.4,
   4038, BILL_MY   , STAT, physical read bytes                                       ,      3.13M,    625.87k,
   4038, BILL_MY   , STAT, db block changes                                          ,          9,        1.8,
   4038, BILL_MY   , STAT, consistent changes                                        ,        469,       93.8,
   4038, BILL_MY   , STAT, free buffer requested                                     ,        392,       78.4,
   4038, BILL_MY   , STAT, CR blocks created                                         ,         10,          2,
   4038, BILL_MY   , STAT, physical reads cache prefetch                             ,          5,          1,
   4038, BILL_MY   , STAT, shared hash latch upgrades - no wait                      ,        375,         75,
   4038, BILL_MY   , STAT, calls to kcmgas                                           ,        376,       75.2,
   4038, BILL_MY   , STAT, redo entries                                              ,          9,        1.8,
   4038, BILL_MY   , STAT, redo size                                                 ,        648,      129.6,
   4038, BILL_MY   , STAT, redo subscn max counts                                    ,          9,        1.8,
   4038, BILL_MY   , STAT, file io wait time                                         ,       4.3M,    860.97k,
   4038, BILL_MY   , STAT, data blocks consistent reads - undo records applied       ,        476,       95.2,
   4038, BILL_MY   , STAT, rollbacks only - consistent read gets                     ,          1,         .2,
   4038, BILL_MY   , STAT, cleanouts and rollbacks - consistent read gets            ,          9,        1.8,
   4038, BILL_MY   , STAT, immediate (CR) block cleanout applications                ,          9,        1.8,
   4038, BILL_MY   , STAT, commit txn count during cleanout                          ,          9,        1.8,
   4038, BILL_MY   , STAT, cleanout - number of ktugct calls                         ,          9,        1.8,
   4038, BILL_MY   , STAT, table scan rows gotten                                    ,        492,       98.4,
   4038, BILL_MY   , STAT, table scan blocks gotten                                  ,         10,          2,
   4038, BILL_MY   , STAT, heap block compress                                       ,         72,       14.4,
   4038, BILL_MY   , TIME, DB CPU                                                    ,    60.99ms,     12.2ms,     1.2%, |@         |
   4038, BILL_MY   , TIME, sql execute elapsed time                                  ,      4.35s,   869.12ms,    86.9%, |@@@@@@@@@ |
   4038, BILL_MY   , TIME, DB time                                                   ,      4.35s,   869.12ms,    86.9%, |@@@@@@@@@ |
   4038, BILL_MY   , WAIT, db file sequential read                                   ,      4.17s,   834.69ms,    83.5%, |@@@@@@@@@ |
   4038, BILL_MY   , WAIT, db file scattered read                                    ,    49.17ms,     9.83ms,     1.0%, |@         |
--  End of Stats snap 1, end=2012-05-21 22:22:16, seconds=5
...省略另两次的采样输出。
&lt;/PRE&gt;&lt;/DIV&gt;&lt;/DIV&gt;
&lt;P&gt;上面的结果是5秒左右的会话采样数据。再一次提醒，涉及到时间，特别要精确到毫秒的，不一定很精确，我们主要是看数据之间的对比。从上面的数据来看，会话请求了382次IO请求，单块读和多块读一共耗时4219.17ms（4.17s+49.17ms），平均每次IO耗时11ms。这个单次IO速度对这套系统的要求来说相对较慢，但也不是慢得很离谱。data blocks consistent reads - undo records applied这个统计值表示进行一致性读时，回滚的UNDO记录条数。&lt;BR&gt;比这个统计值可以很明显地看出，这条SQL在执行时，为了得到一致性读，产生了大量的UNDO记录回滚。那么很显然，在这条SQL语句开始执行的时候，表上有很大的事务还没有提交。当然还有另一种可能是SQL在执行之后有新的很大的事务（不过这种可能性较小一些，因为那样的话这条SQL可能比较快就执行完了）。询问发测试的人员，称没有什么大事务运行过，耳听为虚，眼见为实：&lt;/P&gt;
&lt;DIV class=dp-highlighter&gt;
&lt;DIV class=bar&gt;&lt;PRE style="DISPLAY: none" class=sql name="code"&gt;SQL&amp;gt; select object_id from dba_objects where object_name='MOBILE_CALL_1204_OLD';

 OBJECT_ID
----------
     75858

SQL&amp;gt; select * from v$lock where id1=75858;

no rows selected

SQL&amp;gt; select * from dba_tab_modifications where table_name=upper('MOBILE_call_1204_OLD');

   INSERTS    UPDATES    DELETES TIMESTAMP           TRU DROP_SEGMENTS
---------- ---------- ---------- ------------------- --- -------------
         0  162696447          0 2012-05-21 22:00:02 NO              0
&lt;/PRE&gt;&lt;/DIV&gt;&lt;/DIV&gt;
&lt;P&gt;这张表目前没有事务，但是曾经update了超过1.6亿条记录。最后一次DML的时间正是这条执行很慢的SQL开始运行之后的时间（这里不能说明最后一次事务量很大，也不能说明最后一次修改对SQL造成了很大影响，但是这里证明了这张表最近的确是修改过，并不是像测试人员说的那样没有修改过）。&lt;/P&gt;
&lt;P&gt;实际上对于这张表要做的操作，我之前是类似的表上是有看过的。这张表的总行数有上亿条，而这张表由于进行数据的人工处理，需要update掉绝大部分的行，update时使用并行处理。那么这个问题到，从时间顺序上来讲，应该如下：&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;在表上有很大的事务，但是还没有提交。 
&lt;LI&gt;问题SQL开始执行查询。 
&lt;LI&gt;事务提交。 
&lt;LI&gt;在检查SQL性能问题时，表上已经没有事务。 &lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;由于update量很大，那么UNDO占用的空间也很大，但是可能由于其他活动的影响，很多UNDO块已经刷出内存，这样在问题SQL执行时，大量的块需要将块回滚到之前的状态（虽然事务开始于查询SQL，但是是在查询SQL开始之后才提交的，一致性读的SCN比较是根据SQL开始的SCN与事务提交SCN比较的，而不是跟事务的开始SCN比较），这样需要访问到大量的UNDO块，但是UNDO块很多已经不在内存中，就不得不从磁盘读入。&lt;/P&gt;
&lt;P&gt;对于大事务，特别是更新或DELETE数千万记录的大事务，在生产系统上尽量避免单条SQL一次性做。这造成的影响特别大，比如：&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;事务可能意外中断，回滚时间很长，事务恢复时过高的并行度可能引起负载增加。 
&lt;LI&gt;表中大量的行长时间被锁住。 
&lt;LI&gt;如果事务意外中断，长时间的回滚（恢复）过程中，可能严重影响SQL性能（因为查询时需要回滚块）。 
&lt;LI&gt;事务还未提交时，影响SQL性能，比如本文中提到的情况。 
&lt;LI&gt;消耗过多UNDO空间。 
&lt;LI&gt;对于DELETE大事务，有些版本的oracle在空闲空间查找上会有问题，导致在INSERT数据时，查找空间导致过长的时间。 
&lt;LI&gt;对于RAC数据库，由于一致性读的代价更大，所以大事务的危害更大。 &lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;那么，现在我们可以知道，全表扫描过程还会产生单块读的情况有，读UNDO块。&lt;BR&gt;对于这条SQL，要解决其速度慢的问题，有两种方案：&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;在表上建个索引，如果类似的SQL还要多次执行，这是最佳方案。 
&lt;LI&gt;取消SQL，重新执行。因为已经没有事务在运行，重新执行只是会产生事务清除，但不会回滚UNDO记录来构建一致性读块。 &lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;继续回到问题，从统计数据来看，每秒只构建了少量的一致性读块（CR block created，table scan blocks gotten这两个值均为2），每秒的table scan rows gotten值为98.4，通过dump数据块可以发现块上的行数基本上在49行左右，所以一致性读块数和行数是匹配的。session logical reads每秒为97.6，由于每回滚一条undo记录都要记录一次逻辑读，这个值跟每秒获取的行数也是匹配的（误差值很小），与data blocks consistent reads - undo records applied的值也是很接近的。问题到这儿，产生了一个疑问，就是单块读较多（超过70），因此可以推测，平均每个undo块只回滚了不到2条的undo记录，同时同一数据块上各行对应的undo记录很分散，分散到了多个undo块中，通常应该是聚集在同一个块或相邻块中，这一点非常奇怪，不过现在已经没有这个环境（undo块已经被其他事务重用），不能继续深入地分析这个问题，就留着一个疑问，欢迎探讨（一个可能的解释是块是由多个并发事务修改的，对于这个案例，不会是这种情况，因为在数据块的dump中没有过多ITL，另外更不太可能是一个块更新了多次，因为表实在很大，在短时间内不可能在表上发生很多次这样的大事务）。&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;在最后，我特别要提到，在生产系统上，特别是OLTP类型的系统上，尽量避免大事务。&lt;/STRONG&gt;&lt;/P&gt;
				&lt;p&gt;&lt;strong&gt;您可能还对下面的文章感兴趣：&lt;/strong&gt;&lt;/p&gt;
				&lt;p&gt;&lt;ol&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=218" target="_blank"&gt;sequential和scattered的含义&lt;/a&gt; [2009-10-18 23:17:14]&lt;/li&gt;&lt;/ol&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/78tyvNSyK1nAEoMXWUhRcPCLJ7E/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/78tyvNSyK1nAEoMXWUhRcPCLJ7E/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/78tyvNSyK1nAEoMXWUhRcPCLJ7E/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/78tyvNSyK1nAEoMXWUhRcPCLJ7E/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/blogreadIT/~4/JNB9cvBvE5o" height="1" width="1"/&gt;</description>
		<content><![CDATA[有一条SQL，这个表上建billing_nbr和start_date的复合索引，这条SQL就能很快执行完（实际上最后也建了索引）。但是这里我们要探讨的是，为什么这么一条简单的SQL语句，执行了超过1小时还没有结果。MOBILE_CALL_1204_OLD这张表的大小约为12GB，以系统的IO能力，正常情况下不会执行这么长的时间。简单地看了一下，系统的CPU以及IO压力都不高。假设单进程全表扫描表，每秒扫描50MB大小（这实际上是一个很保守的扫描速度了），那么只需要245秒就可以完成扫描。]]></content>
	<feedburner:origLink>http://blogread.cn/it/article.php?id=5411</feedburner:origLink></item>
	<item>
		<title>从Go看，语言设计（二）</title>
		<link>http://feedproxy.google.com/~r/blogreadIT/~3/P_q-uESscN0/article.php</link>
		<author>dreamhead</author>
		<pubDate>2012-05-28 13:27:35</pubDate>
		<category domain="http://blogread.cn/it/category.php?id=9">算法</category>
		<guid isPermaLink="false">http://blogread.cn/it/article.php?id=5410</guid>
		<comments>http://blogread.cn/it/article.php?id=5410#comment</comments>
		<description>&lt;p&gt;&lt;strong&gt;标签：&lt;/strong&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://blogread.cn/it/tags.php?tag=Go" target="_blank"&gt;Go&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://blogread.cn/it/tags.php?tag=%E8%AF%AD%E8%A8%80%E8%AE%BE%E8%AE%A1" target="_blank"&gt;语言设计&lt;/a&gt;&lt;/p&gt;&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;书接上文，继续从Go看语言设计。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;STRONG&gt;并发编程&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;从多核CPU进入人们的生活，并发编程就成为编程中的新热点。在许多语言里，并发是由库提供的，而对于Go语言，并发则是语言的一部分。曾经，一说到并发编程，就会让人想到多线程/多进程、共享内存等等。Erlang改变了许多人关于并发编程的认识，基于消息的通信模式如今已逐渐成为新的标配，Go语言选择的也是这种模式。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;首先是启动并发的方式：一个简单的函数，go一下就可以了：&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; go Handle();&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;接下来是消息通信：&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ch := make(chan int)&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; go func() {&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ch &amp;lt;- 0&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }()&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; fmt.Println(&amp;lt;-ch)&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;这里创建了一个通信通道(make(chan int))，有了这个通道，通信的双方就可以彼此发消息。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;STRONG&gt;不显式声明的接口与实现之间的关系&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;或许是我少见多怪，Go语言是我接触到的第一个无需显式声明接口和实现二者关系的强类型语言。比如，定义这样一个接口：&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; type Runnable interface {&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Run()&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;然后，是一个使用了这个接口的函数&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; func RunTo(r Runnable, place string) {&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; r.Run()&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; fmt.Println("Get to " + place)&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;之后，再来定义一个类型：&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; type Person struct {&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; name string&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;这个类型也有一个Run函数：&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; func (p *Person) Run() {&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; fmt.Println(p.name + " is running")&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;从代码层面上，Runnable和Person并没有直接的关系，唯一的关系就是二者都有Run函数。即便如此，我们依然可以把Person当做Runnable来使用：&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; p := new(Person)&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; p.name = "dreamhead"&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; RunTo(p, "Xi\'an")&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;只要实现者拥有接口定义的方法，就可以当做这个接口来用。如果熟悉Ruby这样的动态类型语言，你会发现这种说法几乎同&lt;A href="http://en.wikipedia.org/wiki/Duck_typing" target=_blank&gt;Duck Typing&lt;/A&gt;如出一辙，只不过，在Ruby里没有“接口”而已。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;从实现的角度，这个问题并不难理解，所有这一切都是编译器替我们完成的。如同类型推演一样，编译器让我们不必将重复概念反复来说，同时还保证了，不会有“上错花轿”的情况出现。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;STRONG&gt;小结&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Anders Hejlsberg总结了程序设计语言发展的&lt;A href="http://v.youku.com/v_show/id_XMTk1ODM2NTA4.html" target=_blank&gt;三大趋势&lt;/A&gt;：声明式、动态性和并发。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;声明式，包括函数式编程和DSL。函数式编程自不必说，DSL实际上事关表达性，Go简化代码编写的方式就是在这个方向迈出的步伐。动态性，并不仅仅是动态语言，动态语言与静态语言之间的互相汲取营养，类型推演与不显式声明接口和实现关系，便是向着这个方向迈进。至于并发，无需多提。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;总的说来，Go语言的语言设计本身是符合现代程序设计语言发展趋势的。&lt;/P&gt;
				&lt;p&gt;&lt;strong&gt;您可能还对下面的文章感兴趣：&lt;/strong&gt;&lt;/p&gt;
				&lt;p&gt;&lt;ol&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=5409" target="_blank"&gt;从Go看，语言设计（一）&lt;/a&gt; [2012-05-28 13:26:40]&lt;/li&gt;&lt;/ol&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/DYZ96pe1Hr2ecVY1traV4MoKzJA/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/DYZ96pe1Hr2ecVY1traV4MoKzJA/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/DYZ96pe1Hr2ecVY1traV4MoKzJA/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/DYZ96pe1Hr2ecVY1traV4MoKzJA/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/blogreadIT/~4/P_q-uESscN0" height="1" width="1"/&gt;</description>
		<content><![CDATA[书接上文，继续从Go看语言设计。并发编程从多核CPU进入人们的生活，并发编程就成为编程中的新热点。在许多语言里，并发是由库提供的，而对于Go语言，并发则是语言的一部分。曾经，一说到并发编程，就会让人想到多线程/多进程、共享内存等等。Erlang改变了许多人关于并发编程的认识，基于消息的通信模式如今已逐渐成为新的标配，Go语言选择的也是这种模式。]]></content>
	<feedburner:origLink>http://blogread.cn/it/article.php?id=5410</feedburner:origLink></item>
	<item>
		<title>从Go看，语言设计（一）</title>
		<link>http://feedproxy.google.com/~r/blogreadIT/~3/ZlB-Aj4Yeug/article.php</link>
		<author>dreamhead</author>
		<pubDate>2012-05-28 13:26:40</pubDate>
		<category domain="http://blogread.cn/it/category.php?id=9">算法</category>
		<guid isPermaLink="false">http://blogread.cn/it/article.php?id=5409</guid>
		<comments>http://blogread.cn/it/article.php?id=5409#comment</comments>
		<description>&lt;p&gt;&lt;strong&gt;标签：&lt;/strong&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://blogread.cn/it/tags.php?tag=Go" target="_blank"&gt;Go&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://blogread.cn/it/tags.php?tag=%E8%AF%AD%E8%A8%80%E8%AE%BE%E8%AE%A1" target="_blank"&gt;语言设计&lt;/a&gt;&lt;/p&gt;&lt;P&gt;&lt;A href="http://golang.org/" target=_blank&gt;&lt;FONT color=#0066cc&gt;Go语言&lt;/FONT&gt;&lt;/A&gt;发了正式版，终于像一个正经的东西了，不再需要每次从版本控制里面拿代码编译了。拿来把玩一番，看到了一些有趣的东西，记录一下。&lt;/P&gt;
&lt;P&gt;作为一门现代程序设计语言，Go语言从语言设计上反应出现代程序设计语言一些重要变化。&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;函数成为第一类对象&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;函数式编程已经无可阻挡地成为程序设计语言发展的重要趋势，只要是还在演进之中的程序设计语言，函数式编程都已经成为其重要的一部分，即便是Java这个笨重的大象，也会在Java 8中引入lambda。函数式编程的第一步，就是让函数成为第一类对象，也就是可以把函数作为参数和返回值传递。然后，才会有高阶函数，以及后面的一系列变化。&lt;/P&gt;
&lt;P&gt;下面是一个简单的Map实现：&lt;/P&gt;
&lt;P&gt;&lt;SPAN style="WHITE-SPACE: pre"&gt;&lt;/SPAN&gt;func Map(elements []int, f func(int)(int)) (results []int) {&lt;BR&gt;&lt;SPAN style="WHITE-SPACE: pre"&gt;&lt;/SPAN&gt;results = make([]int, len(elements))&lt;BR&gt;&lt;SPAN style="WHITE-SPACE: pre"&gt;&lt;/SPAN&gt;for i, element := range elements {&lt;BR&gt;&lt;SPAN style="WHITE-SPACE: pre"&gt;&lt;/SPAN&gt;results[i] = f(element)&lt;BR&gt;&lt;SPAN style="WHITE-SPACE: pre"&gt;&lt;/SPAN&gt;}&lt;BR&gt;&lt;SPAN style="WHITE-SPACE: pre"&gt;&lt;/SPAN&gt;return&lt;BR&gt;&lt;SPAN style="WHITE-SPACE: pre"&gt;&lt;/SPAN&gt;}&lt;/P&gt;
&lt;P&gt;调用起来也很简单：&lt;/P&gt;
&lt;P&gt;&lt;SPAN style="WHITE-SPACE: pre"&gt;&lt;/SPAN&gt;result := Map(elements, func(element int) int {&lt;BR&gt;&lt;SPAN style="WHITE-SPACE: pre"&gt;&lt;/SPAN&gt;return element + 1&lt;BR&gt;&lt;SPAN style="WHITE-SPACE: pre"&gt;&lt;/SPAN&gt;})&lt;/P&gt;
&lt;P&gt;稍微多说几句，在&lt;A href="http://www.thoughtworks.com/articles/technology-radar-march-2012" target=_blank&gt;&lt;FONT color=#0066cc&gt;新一期的ThoughtWorks技术雷达&lt;/FONT&gt;&lt;/A&gt;上，函数式Java跃然纸上。我对这个问题的理解是，并不仅仅是要有函数式的语言构造，更应该是将函数式编程的一些理念引入到日常的开发中，比如引用透明性，无状态函数等等，这是个有趣的话题。&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;简化代码编写&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;程序员每天要写很多代码，设计一门程序设计语言，除了要考虑各种各样的语言特性之外，很重要的一点就是，就是让写代码更容易。类型推演和内置数据结构就是在这个方向上的努力，Go语言就提供了这两方面的支持。看看下面这段代码，典型的Java啰嗦代码：&lt;/P&gt;
&lt;P&gt;&lt;SPAN style="WHITE-SPACE: pre"&gt;&lt;/SPAN&gt;List lists = new ArrayList();&lt;BR&gt;&lt;SPAN style="WHITE-SPACE: pre"&gt;&lt;/SPAN&gt;lists.add(0);&lt;BR&gt;&lt;SPAN style="WHITE-SPACE: pre"&gt;&lt;/SPAN&gt;lists.add(1);&lt;BR&gt;&lt;SPAN style="WHITE-SPACE: pre"&gt;&lt;/SPAN&gt;lists.add(2);&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;类型推演&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;动态类型语言很令人羡慕的一点就是，他们的变量不用反反复复地写类型。它们也有让人鄙视的地方，没有类型的变量无法做静态检查，许多错误只能在运行阶段暴露。类型推演给予我们一个鱼与熊掌兼得的机会：既能从繁琐的类型声明中解脱出来，又能拜静态类型所赐，在编译期就可以做很多检查，减小犯错的几率。&lt;/P&gt;
&lt;P&gt;例子：&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; car := new(Car)&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;基本数据结构已不可或缺&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;从语言设计的角度来讲，基本数据结构并不是语言的一部分。但从程序员的角度来说，基本数据结构的缺失会让代码显得无比啰嗦，这是对追求整洁代码之人的折磨。所以，有了人写了&lt;A href="http://code.google.com/p/guava-libraries/" target=_blank&gt;&lt;FONT color=#0066cc&gt;Guava&lt;/FONT&gt;&lt;/A&gt;这样的库，解救水深火热的Java人，下面是前面那段代码的Guava版本：&lt;/P&gt;
&lt;P&gt;&lt;SPAN style="WHITE-SPACE: pre"&gt;&lt;/SPAN&gt;List lists = newArrayList(0, 1, 2);&lt;/P&gt;
&lt;P&gt;Go语言内置了一些数据类型的支持，让代码编写稍微简化了一些，不过，相比于很多语言，它还不够简洁。&lt;/P&gt;
&lt;P&gt;有了类型推演和基本数据结构，前面那段啰嗦的代码在Go中就是这个样子了：&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; elements := []int{1, 2, 3}&lt;/P&gt;
				&lt;p&gt;&lt;strong&gt;您可能还对下面的文章感兴趣：&lt;/strong&gt;&lt;/p&gt;
				&lt;p&gt;&lt;ol&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=5410" target="_blank"&gt;从Go看，语言设计（二）&lt;/a&gt; [2012-05-28 13:27:35]&lt;/li&gt;&lt;/ol&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/xSRfLRy6XKfpMUuepcz8tnboi2Y/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/xSRfLRy6XKfpMUuepcz8tnboi2Y/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/xSRfLRy6XKfpMUuepcz8tnboi2Y/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/xSRfLRy6XKfpMUuepcz8tnboi2Y/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/blogreadIT/~4/ZlB-Aj4Yeug" height="1" width="1"/&gt;</description>
		<content><![CDATA[Go语言发了正式版，终于像一个正经的东西了，不再需要每次从版本控制里面拿代码编译了。拿来把玩一番，看到了一些有趣的东西，记录一下。作为一门现代程序设计语言，Go语言从语言设计上反应出现代程序设计语言一些重要变化。函数成为第一类对象函数式编程已经无可阻挡地成为程序设计语言发展的重要趋势，只要是还在演进之中的程序设计语言，函数式编程都已经成为其重要的一部分，即便是Java这个笨重的大象，也会在Java 8中引入lambda。函数式编程的第一步，就是让函数成为第一类对象，也就是可以把函数作为参数和返回值传递。然后，才会有高阶函数，以及后面的一系列变化。]]></content>
	<feedburner:origLink>http://blogread.cn/it/article.php?id=5409</feedburner:origLink></item>
	<item>
		<title>豆瓣东西上线,及谈谈签到、评论等产品的设计</title>
		<link>http://feedproxy.google.com/~r/blogreadIT/~3/wyP57n4DWBk/article.php</link>
		<author>排头兵</author>
		<pubDate>2012-05-28 13:25:50</pubDate>
		<category domain="http://blogread.cn/it/category.php?id=21">设计思想</category>
		<guid isPermaLink="false">http://blogread.cn/it/article.php?id=5408</guid>
		<comments>http://blogread.cn/it/article.php?id=5408#comment</comments>
		<description>&lt;p&gt;&lt;strong&gt;标签：&lt;/strong&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://blogread.cn/it/tags.php?tag=%E7%AD%BE%E5%88%B0" target="_blank"&gt;签到&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://blogread.cn/it/tags.php?tag=%E8%AF%84%E8%AE%BA" target="_blank"&gt;评论&lt;/a&gt;&lt;/p&gt;&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;在2年前，我模仿豆瓣的架构做了一款产品,点评酒的豆瓣社区—《鸡尾吧》，哈哈，域名没续费，下线了.算是一次产品尝试吧.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 我花了将近3个月的业余时间，差不多第一期点评等功能上线,后面这款产品我没怎么做运营和推广，&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 原因是开发快结束的时候,我猛然发现 豆瓣的产品架构可能不适合一些商品,书籍和电影是非常特殊的商品.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 有些收获，因此记录心得.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;在前面一篇博客中讲述到了豆瓣的电视剧其实做的不够好,究其原因是 电视剧是快消品,是观众茶余饭后，调侃的主要的话题，因此电视剧是一个短时间内会诞生大量话题效应的物,而豆瓣是一个需要时间沉淀的，什么书籍好，什么电影好的一个社区，与这种kill time的快消品物是有冲突的.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 一个用户会 看几年前的电影，而普通用户很难去找几年前的一部电视剧来看，为什么？当所有大众在谈论，《甄嬛传》特别火的时候，老百姓聚集一起讨论里面话题的时候，你告诉别人，电视剧《上海滩》里面的某个故事情节，这是多么的不伦不类的事情呀.因此豆瓣的电视剧做不好，是有原因的，因为电视剧这个物，用豆瓣这个产品架构来设计，是有问题的。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;在上一篇博客中 讲到,豆瓣自己的架构都做不好电视剧. 那么除了电视剧之外，其它东西用豆瓣的架构来做，会怎么样呢？记住我说的豆瓣的架构，你可以认为是沉淀某个物的产品架构，豆瓣的产品架构和大众点评的产品架构都是沉底物的[但大众点评和豆瓣又有区别，大众点评属于小众个性化+精英化主流思想+地理位置+价位的综合体点评机制].&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;最近流行的两个电子商务社区，一个是美丽说，一个是蘑菇街，最近发展很火如日中天.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 这里不探讨这2个社区有什么不完美的地方，对于用户而言，其实蘑菇街和美丽说，通过UGC的机制筛选出了，优质的图片内容，淘宝也是一个卖图片的电子社区，不是电子商务.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 假如没有美丽说，和蘑菇街，我们在淘宝选商品，一般怎么操作？搜索某个物，看价格，看交易记录，购买.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 淘宝购物，你是有很明确的需求的.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;蘑菇街，美丽说，其实解决了逛的需求.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 淘宝是一个大而全的仓库，不仅仅包括女性服装，包包等靠外观决定购买的物. 还包括其他需要口碑沉淀的物.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 外观决定购买的物，是一种大众审美的东西，漂亮的衣服，一般都会觉得好.这种主流价值，大众一眼就能分辨好坏的东西，是不需要评论这种复杂的设计的.不需要评论的还包括，下厨房的菜单设计,只需要简单的签到功能，收藏，喜欢，不喜欢等.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;如果用豆瓣的架构来做这一类商品 衣服或是品牌，是有很大的问题的.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 漂亮的衣服是小众需求吗？不是，所有人对美与丑是有共识的，当一件产品设计的有争议，那么这件产品不是美的.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 品牌是小众需求吗？不是，如果你有能力买iphone，你会去买山寨货 小米或是垃圾货 魅族吗? 不会.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 电子产品是小众需求吗？电子产品更新迭代的速度非常之快，是快消品，不适合沉淀的物，不适合豆瓣的架构，如电视剧一样。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 豆瓣东西，是豆瓣野心的一次实验,从中国互联网做事的同情心来看, 个人还是很希望阿北能成功的,毕竟中国做实事的互联网公司真的不多.不过从理性分析来看，豆瓣这次扩张 会导致大量的 非小众产品进入豆瓣，这是一个问题，看如何去噪了.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;沉淀物的产品设计，需要签到，需要点评.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 衣服、数码产品、电视剧 是不需要沉淀的，因为他们都是快消品，都是与时间有很大关系.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 不需要简单 签到设计. 但需要讨论，发现机制的设计.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;品牌是需要沉淀的，但品牌是靠广告来驱动的东西，和衣服一样，品牌是大众一眼能识别的好坏的物.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 品牌不够小众，品牌是相对大众的物.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;最后我想说的，国内这些抄袭公司的产品经理，抄袭产品的时候，希望多考虑产品本身的差异性.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 我至今不看好 美丽说，蘑菇街这种伪UGC模式的价值. 只能说淘宝在 大众化审美需求物的方面 睡觉开了小差，没有做好这个物搜索的过滤机制而已.美丽说，蘑菇街的用户，看见某件漂亮的衣服时，看到N个人已购买时 ，她会考虑这TMD是谁上传的吗？恐怕不会吧.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 那些抄袭国外瀑布流的公司就更不靠谱了，中国有这么多家庭主妇，有这么多业余时间，有这么审美情调吗？&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 盛大失去了一次做真正无物流物社区的机会，因为哥哥我走了.哈哈.产品原型我还有呢.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 好了，时间不早了，哥几个洗洗睡吧。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 明天早上起来修改口语化的东西….霸气外露呀。&lt;/P&gt;
				&lt;p&gt;&lt;strong&gt;您可能还对下面的文章感兴趣：&lt;/strong&gt;&lt;/p&gt;
				&lt;p&gt;&lt;ol&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=5170" target="_blank"&gt;转发 vs 评论&lt;/a&gt; [2012-04-07 15:07:34]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=3096" target="_blank"&gt;规范用户的评论角色&lt;/a&gt; [2011-01-26 21:12:20]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=2926" target="_blank"&gt;让“提到”、“转发”和“评论”各司其职&lt;/a&gt; [2010-12-28 20:56:16]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=2431" target="_blank"&gt;WordPress模板的image.php&lt;/a&gt; [2010-09-28 09:19:07]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=1906" target="_blank"&gt;电子商务网站“用户评论”模块浅析&lt;/a&gt; [2010-07-09 13:13:20]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=1264" target="_blank"&gt;商品评论的Tag模式&lt;/a&gt; [2010-03-29 08:48:36]&lt;/li&gt;&lt;/ol&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/2ZeC7F3kivjxARse539M_SMdRz8/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/2ZeC7F3kivjxARse539M_SMdRz8/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/2ZeC7F3kivjxARse539M_SMdRz8/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/2ZeC7F3kivjxARse539M_SMdRz8/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/blogreadIT/~4/wyP57n4DWBk" height="1" width="1"/&gt;</description>
		<content><![CDATA[豆瓣自己的架构都做不好电视剧. 那么除了电视剧之外，其它东西用豆瓣的架构来做，会怎么样呢？记住我说的豆瓣的架构，你可以认为是沉淀某个物的产品架构，豆瓣的产品架构和大众点评的产品架构都是沉底物的[但大众点评和豆瓣又有区别，大众点评属于小众个性化+精英化主流思想+地理位置+价位的综合体点评机制].]]></content>
	<feedburner:origLink>http://blogread.cn/it/article.php?id=5408</feedburner:origLink></item>
	<item>
		<title>MySQL driver(驱动) liblbmysql for Go1</title>
		<link>http://feedproxy.google.com/~r/blogreadIT/~3/q8mlHFf8FEE/article.php</link>
		<author>谭俊青</author>
		<pubDate>2012-05-28 13:24:33</pubDate>
		<category domain="http://blogread.cn/it/category.php?id=3">MySQL</category>
		<guid isPermaLink="false">http://blogread.cn/it/article.php?id=5407</guid>
		<comments>http://blogread.cn/it/article.php?id=5407#comment</comments>
		<description>&lt;p&gt;&lt;strong&gt;标签：&lt;/strong&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://blogread.cn/it/tags.php?tag=liblbmysql" target="_blank"&gt;liblbmysql&lt;/a&gt;&lt;/p&gt;&lt;P&gt;Go语言1.0出来之后,原来可用的MySQL驱动在新版本上基本不可用了,于是这几天自己写了个简单的MySQL的驱动,暂不支持prepare,没有implement sql/driver.　或许有能用的上的朋友,所以分享出来.　先介绍用法,后面提供下载链接.&lt;BR&gt;先直接上例子&lt;/P&gt;
&lt;DIV class=dean_ch&gt;package main 
&lt;P&gt;&lt;/P&gt;
&lt;P&gt;import (&lt;BR&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; "log"&lt;BR&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; "liblbmysql"&lt;BR&gt;)&lt;/P&gt;
&lt;P&gt;func main() {&lt;BR&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; settings := make(map[string]interface{})&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; settings["host"] = "localhost"&lt;BR&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; settings["port"] = 3306&lt;BR&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; settings["uname"] = "ivan"&lt;BR&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; settings["pass"] = "******"&lt;BR&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; settings["dbname"] = "test"&lt;BR&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; settings["charset"] = "utf8"&lt;BR&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;BR&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; conn, err := liblbmysql.Connect(settings)&lt;BR&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; if err != nil {&lt;BR&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; log.Fatal("Connect to MySQL error: %v", err)&lt;BR&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; var qr *liblbmysql.QueryResult&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; qr, err = conn.ExecuteFetch("select * from ivan")&lt;BR&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; if err != nil {&lt;BR&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; log.Printf("query error: %v", err)&lt;BR&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; } else {&lt;BR&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; for {&lt;BR&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; m := qr.FetchMap()&lt;BR&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; if m != nil {&lt;BR&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; log.Printf("row map: %v\n", m)&lt;BR&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; } else {&lt;BR&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; break&lt;BR&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;BR&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;BR&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;BR&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; qr.Free()&lt;BR&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; conn.Close()&lt;BR&gt;}&lt;BR&gt;&amp;nbsp;&lt;/P&gt;&lt;/DIV&gt;
&lt;P&gt;&lt;SPAN id=more-1002&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;库名: package liblbmysql, 因此将　liblbmysql.a 保存到对应的pkg目录下,然后　import(“liblbmysql”)即可引入该mysql驱动 
&lt;LI&gt;连接MySQL配置参数:　类型:map[string]interface{}, 可配置的参数有host, port, unix_socket, uname, pass, dbname, charset 分别对应MySQL数据库的ip, 端口, unix socoket, 用户名,密码,初始化数据库,连接字符集. &lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;相关方法\结果集\字段\记录等的类型定义:&lt;/P&gt;
&lt;DIV class=dean_ch&gt;type QueryResult struct {&lt;BR&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Fields &amp;nbsp; &amp;nbsp; &amp;nbsp; []Field&lt;BR&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; RowsAffected uint64&lt;BR&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; InsertId &amp;nbsp; &amp;nbsp; uint64&lt;BR&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Rows &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; [][]interface{}&lt;BR&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; …&lt;BR&gt;} 
&lt;P&gt;&lt;/P&gt;
&lt;P&gt;type Field struct {&lt;BR&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Name string&lt;BR&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Type int64&lt;BR&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; …&lt;BR&gt;}&lt;/P&gt;
&lt;P&gt;func Connect(info map[string]interface{}) (conn *Connection, err error)&lt;/P&gt;
&lt;P&gt;func (this *Connection) Begin() (err error)&lt;/P&gt;
&lt;P&gt;func (this *Connection) Commit() (err error) &lt;/P&gt;
&lt;P&gt;func (this *Connection) Rollback() (err error)&lt;/P&gt;
&lt;P&gt;func (this *Connection) ExecuteFetch(query string) (qr *QueryResult, err error)&lt;/P&gt;
&lt;P&gt;func (qr *QueryResult) FetchRow() []interface{}&lt;/P&gt;
&lt;P&gt;func (qr *QueryResult) FetchRows() [][]interface{}&lt;/P&gt;
&lt;P&gt;func (qr *QueryResult) FetchMap() map[string]interface{}&lt;/P&gt;
&lt;P&gt;func (qr *QueryResult) Free()&lt;BR&gt;&amp;nbsp;&lt;/P&gt;&lt;/DIV&gt;
&lt;P&gt;这里QueryResult的Fetch函数返回的字段记录都是字符串结果,为了统一暂时没有将结果转换成Go语言中对应的数据类型,也是为了统一,方便程序员自己转换处理.&lt;/P&gt;
&lt;P&gt;liblbmysql　下载地址:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Mac 64: &lt;A href="http://legendbase.com/products/liblbmysql/mac64/liblbmysql.a"&gt;&lt;FONT color=#0066cc&gt;http://legendbase.com/products/liblbmysql/mac64/liblbmysql.a&lt;/FONT&gt;&lt;/A&gt; 
&lt;LI&gt;Win 32: &lt;A href="http://legendbase.com/products/liblbmysql/win32/liblbmysql.a"&gt;&lt;FONT color=#0066cc&gt;http://legendbase.com/products/liblbmysql/win32/liblbmysql.a&lt;/FONT&gt;&lt;/A&gt; 
&lt;LI&gt;Win 64: 
&lt;LI&gt;Linux 32: 
&lt;LI&gt;Linux 64: &lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;PS: liblbmysql 取名由来 LegendBase driver for MySQL&lt;/P&gt;
				&lt;p&gt;&lt;strong&gt;您可能还对下面的文章感兴趣：&lt;/strong&gt;&lt;/p&gt;
				&lt;p&gt;很抱歉，暂时没有...... &lt;/p&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/u6vamzrXLpHSIgEJUr9_4ldLxYo/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/u6vamzrXLpHSIgEJUr9_4ldLxYo/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/u6vamzrXLpHSIgEJUr9_4ldLxYo/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/u6vamzrXLpHSIgEJUr9_4ldLxYo/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/blogreadIT/~4/q8mlHFf8FEE" height="1" width="1"/&gt;</description>
		<content><![CDATA[Go语言1.0出来之后,原来可用的MySQL驱动在新版本上基本不可用了,于是这几天自己写了个简单的MySQL的驱动,暂不支持prepare,没有implement sql/driver.　或许有能用的上的朋友,所以分享出来.　先介绍用法,后面提供下载链接. ]]></content>
	<feedburner:origLink>http://blogread.cn/it/article.php?id=5407</feedburner:origLink></item>
	<item>
		<title>利用tcpcopy引流做模拟在线测试</title>
		<link>http://feedproxy.google.com/~r/blogreadIT/~3/n-abpVY7Yks/article.php</link>
		<author>春度</author>
		<pubDate>2012-05-28 13:24:10</pubDate>
		<category domain="http://blogread.cn/it/category.php?id=15">网络系统</category>
		<guid isPermaLink="false">http://blogread.cn/it/article.php?id=5406</guid>
		<comments>http://blogread.cn/it/article.php?id=5406#comment</comments>
		<description>&lt;p&gt;&lt;strong&gt;标签：&lt;/strong&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://blogread.cn/it/tags.php?tag=tcpcopy" target="_blank"&gt;tcpcopy&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://blogread.cn/it/tags.php?tag=%E6%B5%8B%E8%AF%95" target="_blank"&gt;测试&lt;/a&gt;&lt;/p&gt;&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;一、工具介绍&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Tcpcopy是一个分布式在线压力测试工具，可以将线上流量拷贝到测试机器，实时的模拟线上环境，达到在程序不上线的情况下实时承担线上流量的效果，尽早发现bug，增加上线信心。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Tcpcopy是由网易技术部于2011年9月开源的一个项目，现在已经更新到0.4版本。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;与传统的压力测试工具(如：abench)相比，tcpcopy的最大优势在于其实时及真实性，除了少量的丢包，完全拷贝线上流量到测试机器，真实的模拟线上流量的变化规律。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;二、Tcpcopy的原理&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;1．流程&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;现在以nginx作为前端说明tcpcopy的原理：&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;A href="http://www.searchtb.com/wp-content/uploads/2012/05/tcpcopy运行原理图2.jpg"&gt;&lt;IMG class="alignnone size-full wp-image-1957" alt="" src="http://www.searchtb.com/wp-content/uploads/2012/05/tcpcopy运行原理图2.jpg"&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;上图中左边是线上前端机，右边是测试前端机。线上前端机开启tcpcopy客户端(tcpcopy进程)，测试前端机开启tcpcopy服务端(interception进程)，且两台机器上都启动了nginx服务。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Tcpcopy拷贝一次流量访问的步骤如下：&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;①　一个访问到达线上前端机；&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;②　socket包在ip层被拷贝了一份传给tcpcopy进程；&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;③　tcpcopy修改包的目的及源地址，发给测试前端机；&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;④　拷贝的包到达测试前端机；&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;⑤　测试前端机的nginx处理访问，并返回结果；&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;⑥　返回结果在ip层被截获、丢弃，由intercpetion拷贝返回结果的ip&amp;nbsp;header返回；&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;⑦　ip&amp;nbsp;header被发送给线上前端机的tcpcopy进程。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;1．代码分析&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;1)&amp;nbsp;首先，在链路层或者IP层，在把包交到上一层之前，系统会检查有没进程创建了socket(AF_PACKET,SOCK_DGRAM,…)或socket(AF_INET,SOCK_RAW,…)等类型的套接字(即原始套接字sock_raw)，如果有，这个包就会被复制一份并发送到这个socket的缓冲区。tcpcopy就是通过这种方式来复制访问流量的。上述的两种抓包方式，前者工作在数据链路层，后者工作在IP层。在tcpcopy中不同版本所使用的抓包函数不同，在0.3版本中是：&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;int&amp;nbsp;sock&amp;nbsp;=&amp;nbsp;socket(AF_PACKET,SOCK_RAW,htons(ETH_P_IP));&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;而在0.4版本中，用的是：&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;int&amp;nbsp;sock&amp;nbsp;=&amp;nbsp;socket(AF_INET,SOCK_RAW,IPPROTO_TCP);&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;以上两个函数分别工作在链路层和IP层，前者会把进来和出去的包都抓取到，后者只 抓取到进来的包。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;2) Tcpcopy在发送拷贝的数据包的时候，使用了如下socket：&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sock&amp;nbsp;=&amp;nbsp;socket(AF_INET,&amp;nbsp;SOCK_RAW,IPPROTO_RAW);&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;并对这个socket设置了IP_HDRINCL：&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;setsockopt(sock,&amp;nbsp;IPPROTO_IP,&amp;nbsp;IP_HDRINCL,&amp;nbsp;&amp;amp;n,&amp;nbsp;sizeof(n));&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;因此网络层不会再增加ip&amp;nbsp;header.&amp;nbsp;发送之前更改了包的目的ip和端口：&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;tcp_header-&amp;gt;dest&amp;nbsp;=&amp;nbsp;remote_port;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ip_header-&amp;gt;daddr&amp;nbsp;=&amp;nbsp;remote_ip;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;最后调用sendto函数发送包到测试前端机：&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;send_len&amp;nbsp;=&amp;nbsp;sendto(sock,(char&amp;nbsp;*)ip_header,tot_len,0,&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(struct&amp;nbsp;sockaddr&amp;nbsp;*)&amp;amp;toaddr,sizeof(toaddr));&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;3)&amp;nbsp;在测试前端机上加载了ip_queue模块，并设置iptables规则：&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;iptables&amp;nbsp;-I&amp;nbsp;OUTPUT&amp;nbsp;-p&amp;nbsp;tcp&amp;nbsp;-sport&amp;nbsp;80&amp;nbsp;-j&amp;nbsp;QUEUE&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;复制的访问流量到达测试前端机上的nginx，nginx处理并返回结果，这个结果包在IP层会被前面所设置的iptables规则匹配发往目标(target)QUEUE。而QUEUE是由ip_queue模块实现。下一步这个匹配包就会被内核经过netlink&amp;nbsp;socket发往用户空间的程序(在这是tcpcopy的服务端interception进程)。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;netlink&amp;nbsp;socket是内核与用户进程之间的一种通信机制，是网络应用程序与内核通信的最常用的接口，可以用来配置网络的各个方面(比如包的过滤)。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;interception用如下方式创建netlink&amp;nbsp;socket：&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;int&amp;nbsp;sock&amp;nbsp;=&amp;nbsp;socket(AF_NETLINK,SOCK_RAW,NETLINK_FIREWALL);&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;NETLINK_FIREWALL协议有三种消息类型：IPQM_MODE,IPQM_PACKET,IPQM_VERDICT.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;内核通过一个IPQM_PACKET消息将刚才截获的返回结果包发送到interception,interception给内核发送一个IPQM_VERDICT消息告诉内核对这个包的裁决结果(DROP,ACCEPT,etc.)。tcpcopy通过这样的办法将测试前端机上nginx返回的结果截获丢弃，并由interception返回一个ip&amp;nbsp;header.相应代码实现如下：&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;拷贝结果包的ip&amp;nbsp;header，发送：&lt;/P&gt;&lt;PRE class="brush: java; title: ;"&gt;struct&amp;nbsp;receiver_msg_st&amp;nbsp;msg;

...

memset(&amp;amp;msg,0,sizeof(struct&amp;nbsp;receiver_msg_st));

memcpy((void&amp;nbsp;*)&amp;nbsp;&amp;amp;(msg.ip_header),ip_header,sizeof(struct&amp;nbsp;iphdr));

memcpy((void&amp;nbsp;*)&amp;nbsp;&amp;amp;(msg.tcp_header),tcp_header,sizeof(struct&amp;nbsp;tcphdr));

...

send(sock,(const&amp;nbsp;void&amp;nbsp;*)msg,sizeof(struct&amp;nbsp;receiver_msg_st),0);
&lt;/PRE&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;interception向内核发送IPQM_VERDICT消息报告裁决结果：&lt;/P&gt;&lt;PRE class="brush: java; title: ;"&gt;struct&amp;nbsp;nlmsghdr*&amp;nbsp;nl_header=(struct&amp;nbsp;nlmsghdr*)buffer;

struct&amp;nbsp;ipq_verdict_msg&amp;nbsp;*ver_data&amp;nbsp;=&amp;nbsp;NULL;

struct&amp;nbsp;sockaddr_nl&amp;nbsp;addr;

nl_header-&amp;gt;nlmsg_type=IPQM_VERDICT;

nl_header-&amp;gt;nlmsg_len=NLMSG_LENGTH(sizeof(struct&amp;nbsp;ipq_verdict_msg));

nl_header-&amp;gt;nlmsg_flags=(NLM_F_REQUEST);

nl_header-&amp;gt;nlmsg_pid=getpid();

nl_header-&amp;gt;nlmsg_seq=seq++;

ver_data=(struct&amp;nbsp;ipq_verdict_msg&amp;nbsp;*)NLMSG_DATA(nl_header);

ver_data-&amp;gt;value=NF_DROP;&amp;nbsp;/*如果要accept这个包，则设为NF_ACCEPT)*/

ver_data-&amp;gt;id=packet_id;

memset(&amp;amp;addr,0,sizeof(addr));

addr.nl_family&amp;nbsp;=&amp;nbsp;AF_NETLINK;

addr.nl_pid&amp;nbsp;=&amp;nbsp;0;

addr.nl_groups&amp;nbsp;=&amp;nbsp;0;

sendto(firewall_sock,(void&amp;nbsp;*)nl_header,nl_header-&amp;gt;nlmsg_len,0,

(struct&amp;nbsp;sockaddr&amp;nbsp;*)&amp;amp;addr,sizeof(struct&amp;nbsp;sockaddr_nl));
&lt;/PRE&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;内核接收到这个包后将packet_id这个包drop或accept。在后文中可以看到从0.4版本开始的tcpcopy利用这个特点保留了一个允许访问的ip列表，因为默认情况下访问测试前端机上nginx服务所得到的结果会在ip层被drop掉，造成在80端口上无法访问nginx。有了这个允许ip列表，即使是刷了iptables规则、起了interception进程，在某些机器上也是可以正常访问测试前端机上的nginx服务的。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;三、操作方法&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;下载地址：&lt;A href="http://tcpcopy.googlecode.com/files/tcpcopy-0.3.3.tar.gz"&gt;http://tcpcopy.googlecode.com/files/tcpcopy-0.3.3.tar.gz&lt;/A&gt;，下载tcpcopy源码包后解压，执行常规的./configure;make;make&amp;nbsp;install三部曲即可。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;假如有两台机器：&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;机器A：线上前端机，ip：61.135.xxx.1；&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;机器B：测试前端机，ip：61.135.xxx.2；&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;两台机器上都起了nginx服务，操作者在两台机器上都需有sudo权限。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;操作步骤：&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;1.&amp;nbsp;在B依次执行，&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;1)&amp;nbsp;加载ip_queue模块，modprobe&amp;nbsp;ip_queue；&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;2)&amp;nbsp;配置iptables规则，sudo&amp;nbsp;iptables&amp;nbsp;-t&amp;nbsp;filter&amp;nbsp;-I&amp;nbsp;OUTPUT&amp;nbsp;-p&amp;nbsp;tcp&amp;nbsp;-sport&amp;nbsp;80&amp;nbsp;-j&amp;nbsp;QUEUE；&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;3)&amp;nbsp;启动tcpcopy服务端，sudo&amp;nbsp;./interception&amp;nbsp;&amp;amp;&amp;nbsp;；&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;2.&amp;nbsp;在A上执行，&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;启动tcpcopy客户端，sudo&amp;nbsp;./tcpcopy&amp;nbsp;61.135.xxx.1&amp;nbsp;80&amp;nbsp;61.135.xxx.2&amp;nbsp;80&amp;nbsp;&amp;amp;；&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;如果在A上看到“I&amp;nbsp;am&amp;nbsp;booted”，则表示操作成功，tcpcopy已经开始工作，可以查看一下机器B上nginx的日志确认。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;四、高级用法&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;1.&amp;nbsp;级联&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;设有线上前端机一台命名A，测试前端机若干B,C,D,……利用tcpcopy可以将A上的访问流量拷贝到B，B拷贝到C，C拷贝到D，……这样就将一份流量放大了多倍，可以用来测试引擎的极限承受能力。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;2.&amp;nbsp;同一tcpcopy实例内多重复制&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;从0.4版开始，tcpcopy支持在同一个客户端实例复制多份请求到同一个服务端，启动的方式如下(比如要复制2份，使用-n这个选项来控制要复制的份数)，&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sudo&amp;nbsp;./tcpcopy&amp;nbsp;61.135.xxx.1&amp;nbsp;80&amp;nbsp;61.135.xxx.2&amp;nbsp;80；&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sudo&amp;nbsp;./tcpcopy&amp;nbsp;61.135.xxx.1&amp;nbsp;80&amp;nbsp;61.135.xxx.2&amp;nbsp;80&amp;nbsp;-n&amp;nbsp;1;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sudo&amp;nbsp;./tcpcopy&amp;nbsp;61.135.xxx.1&amp;nbsp;80&amp;nbsp;61.135.xxx.2&amp;nbsp;80&amp;nbsp;-n&amp;nbsp;2;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;3.&amp;nbsp;服务端允许访问ip列表&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;由于配置了iptables规则，使用tcp协议且源端口号为80的包都会被匹配放到目标QUEUE去，进而被drop掉，因此这个时候测试前端机上的nginx服务是不可访问的。从0.4版本开始，可以指定一个允许访问ip列表，在列表中的机器上是可以访问测试前端机上的nginx服务的。假如要添加61.135.xxx.3，61.135.xxx.4到允许ip列表，启动interception时使用如下方式：&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sudo&amp;nbsp;./interception&amp;nbsp;61.135.xxx.3:61.135.xxx.4；&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;五、tcpcopy在一淘的应用&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;一淘引擎在今年2月份时有一次重大的更新，在上线之前，利用tcpcopy把所有前端机的流量拷贝到新的demo前端机上，进行在线模拟实验。引流示例如下图：&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;A href="http://www.searchtb.com/wp-content/uploads/2012/05/测试引流示意图1.jpg"&gt;&lt;IMG class="alignnone size-full wp-image-1958" alt="" src="http://www.searchtb.com/wp-content/uploads/2012/05/测试引流示意图1.jpg"&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;所有线上前端机都开启tcpcopy客户端，由于一直报”Message&amp;nbsp;too&amp;nbsp;long”(这是由于packets长度超过1500造成，每分钟差不多有50个)刷屏，所以将stderror重定向，&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sudo&amp;nbsp;./tcpcopy&amp;nbsp;ipA&amp;nbsp;80&amp;nbsp;ipB&amp;nbsp;80&amp;nbsp;2&amp;gt;/dev/null&amp;nbsp;&amp;amp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;在测试前端机上开启tcpcopy服务端程序interception，并设置iptables规则。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;压了大约有一个星期，期间观察qps，load等各项指标是否正常。新引擎单个集群一天的平均qps大约是110，峰值大约240。实验结果显示的包丢失率大约是(1822213-1797242)/1822213=1.37%.&amp;nbsp;后来进一步将多个线上前端机的流量引到一个测试前端，测试新引擎的单集群极限服务能力，qps能达到1000以上，&amp;nbsp;latency大约40ms，达到了上线要求。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Tcpcopy客户端和服务端本身占用的资源较少，不影响在线服务。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;13991&amp;nbsp;root&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;20&amp;nbsp;&amp;nbsp;&amp;nbsp;0&amp;nbsp;&amp;nbsp;160m&amp;nbsp;&amp;nbsp;77m&amp;nbsp;&amp;nbsp;888&amp;nbsp;R&amp;nbsp;&amp;nbsp;7.7&amp;nbsp;&amp;nbsp;0.3&amp;nbsp;&amp;nbsp;71:26.24&amp;nbsp;tcpcopy&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;7723&amp;nbsp;root&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;15&amp;nbsp;&amp;nbsp;&amp;nbsp;0&amp;nbsp;42592&amp;nbsp;&amp;nbsp;38m&amp;nbsp;&amp;nbsp;324&amp;nbsp;S&amp;nbsp;&amp;nbsp;5.8&amp;nbsp;&amp;nbsp;0.2&amp;nbsp;&amp;nbsp;12:14.83&amp;nbsp;interception&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;%cpu分别占7.7%和5.8%，物理内存占用分别是77m和38m.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;由于几乎完全模拟了线上环境，我们对于新引擎上线更有信心，最终上线圆满成功，实现平稳过渡。现在利用tcpcopy拷贝线上流量作模拟压测已成为我们日常开发上线流程中的一项内容。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;六、附录&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;项目主页：&lt;A href="http://code.google.com/p/tcpcopy/"&gt;http://code.google.com/p/tcpcopy/&lt;/A&gt;；&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Sock_raw：&lt;A href="http://sock-raw.org/papers/sock_raw"&gt;http://sock-raw.org/papers/sock_raw&lt;/A&gt;；&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Netlink：&lt;A href="http://smacked.org/docs/netlink.pdf"&gt;http://smacked.org/docs/netlink.pdf&lt;/A&gt;；&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;相关主题：&lt;A href="http://blog.csdn.net/wangbin579/article/category/926096/1"&gt;http://blog.csdn.net/wangbin579/article/category/926096/1&lt;/A&gt; ；&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;代码svn地址：&lt;A href="http://tcpcopy.googlecode.com/svn/trunk"&gt;http://tcpcopy.googlecode.com/svn/trunk&lt;/A&gt;；&lt;/P&gt;
				&lt;p&gt;&lt;strong&gt;您可能还对下面的文章感兴趣：&lt;/strong&gt;&lt;/p&gt;
				&lt;p&gt;&lt;ol&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=5405" target="_blank"&gt;为什么TDD？&lt;/a&gt; [2012-05-28 13:23:26]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=5206" target="_blank"&gt;我们需要专职的QA吗？&lt;/a&gt; [2012-04-12 13:34:02]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=4901" target="_blank"&gt;安全测试与渗透测试区别&lt;/a&gt; [2012-01-29 20:48:29]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=4679" target="_blank"&gt;工具分享：20个免费的网站测试工具&lt;/a&gt; [2011-12-18 22:17:27]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=4597" target="_blank"&gt;敏捷测试的方法和实践&lt;/a&gt; [2011-11-16 23:38:49]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=4304" target="_blank"&gt;可用性测试的权衡之道（一）&lt;/a&gt; [2011-09-07 23:12:26]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=4158" target="_blank"&gt;测试驱动开发(TDD)跟敏捷开发有冲突&lt;/a&gt; [2011-08-14 16:04:38]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=4013" target="_blank"&gt;12款很棒的浏览器兼容性测试工具推荐&lt;/a&gt; [2011-07-18 12:19:22]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=3959" target="_blank"&gt;给Apache做压力测试时遇到的问题&lt;/a&gt; [2011-07-06 23:44:05]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=3749" target="_blank"&gt;如何快速解除用户防备？――浅谈可用性测试中沟通的技巧&lt;/a&gt; [2011-06-02 22:41:30]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=3733" target="_blank"&gt;使用gcov完成代码覆盖率的测试&lt;/a&gt; [2011-06-02 13:31:39]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=3685" target="_blank"&gt;使用windows7的virtual PC打造原装IE6、IE7、IE8测试环境&lt;/a&gt; [2011-06-01 23:34:50]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=3654" target="_blank"&gt;Super Smack&lt;/a&gt; [2011-05-30 13:52:59]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=3557" target="_blank"&gt;你真正需要的代码测试覆盖率是多少？&lt;/a&gt; [2011-04-28 13:39:03]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=3364" target="_blank"&gt;淘宝霜波说测试（一）&lt;/a&gt; [2011-03-01 22:42:42]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=3083" target="_blank"&gt;简单快速的可用性测试&lt;/a&gt; [2011-01-25 22:32:27]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=3002" target="_blank"&gt;详解黑盒、白盒、灰盒测试&lt;/a&gt; [2011-01-12 23:15:29]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=2945" target="_blank"&gt;在 Linux 的应用中测试中的延时和丢包模拟&lt;/a&gt; [2010-12-30 22:46:10]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=2893" target="_blank"&gt;node.js调研与服务性能测试&lt;/a&gt; [2010-12-21 23:10:28]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=2804" target="_blank"&gt;不用设置host，访问测试的http接口&lt;/a&gt; [2010-12-07 02:40:41]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=2745" target="_blank"&gt;Hadoop现有测试框架探幽&lt;/a&gt; [2010-11-24 23:01:46]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=2669" target="_blank"&gt;Latch free竞争 - 最近的SAP测试项目小记&lt;/a&gt; [2010-11-10 02:17:26]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=2634" target="_blank"&gt;【社会化设计】自我（self）部分――邀请测试版本（private beta）&lt;/a&gt; [2010-11-01 20:00:55]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=2538" target="_blank"&gt;兼顾安全及易用性的远程测试系统之搭建&lt;/a&gt; [2010-10-21 08:50:28]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=2428" target="_blank"&gt;在线测试不同操作系统不同浏览器网页的显示效果&lt;/a&gt; [2010-09-27 08:51:02]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=2414" target="_blank"&gt;A/B测试：实现方法&lt;/a&gt; [2010-09-26 22:23:45]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=2377" target="_blank"&gt;A/B测试：基本概念&lt;/a&gt; [2010-09-12 23:37:09]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=2372" target="_blank"&gt;软件测试工程师的职业素质&lt;/a&gt; [2010-09-09 22:06:23]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=2370" target="_blank"&gt;什么样的测试用例是好的&lt;/a&gt; [2010-09-09 22:04:42]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=2005" target="_blank"&gt;Xvfb+YSlow+ShowSlow搭建前端性能测试框架&lt;/a&gt; [2010-07-20 09:55:44]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=1914" target="_blank"&gt;WEB性能测试工具推荐&lt;/a&gt; [2010-07-12 23:27:11]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=1853" target="_blank"&gt;压力测试软件 Siege 的正确用法&lt;/a&gt; [2010-06-25 12:19:51]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=1794" target="_blank"&gt;apache下ab网站压力测试命令的参数、输出结果的中文注解&lt;/a&gt; [2010-06-17 10:15:05]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=1440" target="_blank"&gt;服务器性能测试工具推荐&lt;/a&gt; [2010-04-23 10:27:07]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=1371" target="_blank"&gt;自动化测试中Python与C/C++的混合使用&lt;/a&gt; [2010-04-14 13:31:21]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=1222" target="_blank"&gt;MySQL不同分支版本的压力测试&lt;/a&gt; [2010-03-18 09:02:29]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=936" target="_blank"&gt;自动化测试之惑&lt;/a&gt; [2010-01-07 13:29:01]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=797" target="_blank"&gt;Btrfs 测试结果简述&lt;/a&gt; [2009-12-10 13:43:43]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=787" target="_blank"&gt;如何当好测试组长(1)-制定测试计划&lt;/a&gt; [2009-12-08 23:10:19]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=623" target="_blank"&gt;性能测试工具sysbench简介&lt;/a&gt; [2009-11-18 09:29:55]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=349" target="_blank"&gt;mysql基本连接,mysqli,pdo,adodb,pearDB之间的区别，速度测试&lt;/a&gt; [2009-10-28 22:41:37]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=323" target="_blank"&gt;在生产环境中使用php性能测试工具xhprof&lt;/a&gt; [2009-10-27 08:58:40]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=91" target="_blank"&gt;在linux下常用的硬件测试软件&lt;/a&gt; [2009-10-12 09:13:03]&lt;/li&gt;&lt;/ol&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/Y3KxIXlPdGpMsCKtuasGMxzJzG8/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Y3KxIXlPdGpMsCKtuasGMxzJzG8/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/Y3KxIXlPdGpMsCKtuasGMxzJzG8/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Y3KxIXlPdGpMsCKtuasGMxzJzG8/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/blogreadIT/~4/n-abpVY7Yks" height="1" width="1"/&gt;</description>
		<content><![CDATA[一、工具介绍 Tcpcopy是一个分布式在线压力测试工具，可以将线上流量拷贝到测试机器，实时的模拟线上环境，达到在程序不上线的情况下实时承担线上流量的效果，尽早发现bug，增加上线信心。 Tcpcopy是由网易技术部于2011年9月开源的一个项目，现在已经更新到0.4版本。与传统的压力测试工具（如：abench）相比，tcpcopy的最大优势在于其实时及真实性，除了少量的丢包，完全拷贝线上流量到测试机器，真实的模拟线上流量的变化规律。二、Tcpcopy的原理 1．流程现在以nginx作为前端说明tcpcopy的原理： 上图中左边是线上前端机，右边是测试前端机。线上前端机开启tcpcopy客户端（tcpcopy进程），测试前端机开启tcpcopy服务端（interception进程），且两台机器上都启动了nginx服务。 ]]></content>
	<feedburner:origLink>http://blogread.cn/it/article.php?id=5406</feedburner:origLink></item>
	<item>
		<title>为什么TDD？</title>
		<link>http://feedproxy.google.com/~r/blogreadIT/~3/iufb9wC6yDc/article.php</link>
		<author>zhangkf</author>
		<pubDate>2012-05-28 13:23:26</pubDate>
		<category domain="http://blogread.cn/it/category.php?id=8">其他</category>
		<guid isPermaLink="false">http://blogread.cn/it/article.php?id=5405</guid>
		<comments>http://blogread.cn/it/article.php?id=5405#comment</comments>
		<description>&lt;p&gt;&lt;strong&gt;标签：&lt;/strong&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://blogread.cn/it/tags.php?tag=TDD" target="_blank"&gt;TDD&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://blogread.cn/it/tags.php?tag=%E6%B5%8B%E8%AF%95" target="_blank"&gt;测试&lt;/a&gt;&lt;/p&gt;&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;1. 反映真实需求&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;这里存在先写测试和后写测试的区别。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;先说后写测试。根据很多经验，在直接写产品实现代码时，需要考虑需求，同时需要兼顾实现的细节，用什么算法和语法。在对需求和考虑和实现细节间来回，很容易让人产生对其中一方的疏忽，遗漏掉一些需求方面，甚至在实现上存在缺陷。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;有人会说我可以通过后写测试来保证。第一经验是，很多人都不会在实现完成后，补充测试，因为还有更多的工作和需求需要实现。第二是开发人员很容易在后补的测试中，只是试图去测试他已有的实现，而不是需求本身，很容易遗漏掉一些边界检查之类，在测试时，已有的实现细节会在脑子里面先入为主，即使实现存在问题或有漏洞，也很难在后补的测试中测出来。我阅读过很多面试者的测试代码，很明显都是后补的，因为一些很明显的问题没有测出来，甚至已经实现的逻辑也是只测试了一部分。而这些面试者都承认。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;结果就是，一旦代码签入，开始集成之后，暴露出问题，后补的测试起不到对于实现代码的保障需求的作用，开发者不能不借助调试工具，单步跟踪实现代码的每一行去寻找问题发生的原因。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;再说先写测试。按照TDD的流程，先写失败的测试，再写恰好让测试成功的实现代码，最后重构，如此往复。这样的好处在于，每先写一个测试，都是在试图用自己对问题和需求的理解，来定义实现代码的架子。从测试的不同角度，范围、边界、大小、功能等等，来定义实现代码将来会是个什么样子。一个测试接着一个测试，利用TDD的过程，把实现代码恰好不多不少，正好驱动出解决这个需求和问题的实现代码来。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;这里的重点在于，先写测试可以让开发者把重点放在理解需求和实现需求上，而不是一开始就陷入实现的细节中同时兼顾需求，掉入两者都兼顾不好的境地。先写的测试代码，作为副产品，可以作为验证需求的得力保障。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;2. 设计在其中&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;先写测试对于设计的好处在于，先写测试先定义新的类，以及定义类与类之间的关系，就是在定义类与类之间如何交互，每个类如何暴露自己的接口，类和类之间的引用关系。这时，测试代码会逼迫开发者认真考虑如何分解类与类之间的耦合关系，这样产生的实现代码更容易利用了IoC和DIP的模式，实现面向接口编程。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;这样实现代码的好处还在于，代码的可测试性很高，在加入更多的测试代码和新类的时候，同样借力于已有类的面向接口和依赖反转所带来的可测试性，达到新实现代码的面向接口和可测试性，这样进入良性循环。而这对于整体的代码和设计，获益良多。换句话说，测试即设计。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;回头看后写测试的情况，因为从一开始开发者把重心放在实现的细节和功能需求的往复上，对于代码设计、类的关系和定义很容易疏于考虑，产生的结果可能是耦合紧，可测试性差。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;3. 增强信心&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;在我看来，软件开发周期、软件交付最大的问题在于交付后的运行和维护阶段，正是这个阶段才是软件在持续交付价值的时期。在软件的可维护性，在这个阶段凸显价值。在软件交付后，包括软件开发周期期间，不可避免的就是开发者在根据新的需求，逐渐添加新的功能代码，或者修复一些已知的缺陷。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;很多经验表明，在开发者按照需求添加一些新的代码进入系统，或者试图修复已有缺陷时，很容易导致既有功能出错，也就是新引入的代码打破了既有代码的逻辑，导致回归问题的出现。因为软件系统的可测试性差，无法做到快速频繁自动的回归测试，带来的可维护性自然也很差。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;而作为TDD的副产品之一——可以快速频繁自动运行的测试代码，可以在开发者新引入代码之际，给予开发者足够的信心，每次添加一点新代码，一个方法，一个类，都已频繁运行已有相关的测试代码，来确保新引入代码不会打破已有的功能。这也是《重构》里面反复提到的在每个重构小步骤后都要运行所有的测试代码的原因所在。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;4. 粒度和进度&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;按照TDD的原则，先写测试，可以让开发者在同一时间只关注在功能需求的一小部分，把功能需求且分到一定小的粒度，用测试代码去表示这样的需求，用实现代码让测试通过，实现这样的需求，然后重构。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;这样的好处在于，开发者自己的注意力和重心不用在整个功能需求内的小需求点之间犹豫，每次注重解决单个小问题，解决完一个进入下一个小问题的解决。在保证小粒度实现的同时，保证进度可以随时被打断，但同时被打断时已经做完的是完整可以运行，至少是实现了部分需求的实现代码。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;而后写测试的代价是，首先实现代码很有可能包含设计上的缺陷，甚至含有缺陷，在完美的测试代码完成之前(事实上这是不可能的)，可以交付的是可能存在严重缺陷，甚至是曲解了功能需求的实现代码。&lt;/P&gt;
				&lt;p&gt;&lt;strong&gt;您可能还对下面的文章感兴趣：&lt;/strong&gt;&lt;/p&gt;
				&lt;p&gt;&lt;ol&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=5406" target="_blank"&gt;利用tcpcopy引流做模拟在线测试&lt;/a&gt; [2012-05-28 13:24:10]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=5206" target="_blank"&gt;我们需要专职的QA吗？&lt;/a&gt; [2012-04-12 13:34:02]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=4901" target="_blank"&gt;安全测试与渗透测试区别&lt;/a&gt; [2012-01-29 20:48:29]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=4679" target="_blank"&gt;工具分享：20个免费的网站测试工具&lt;/a&gt; [2011-12-18 22:17:27]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=4597" target="_blank"&gt;敏捷测试的方法和实践&lt;/a&gt; [2011-11-16 23:38:49]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=4304" target="_blank"&gt;可用性测试的权衡之道（一）&lt;/a&gt; [2011-09-07 23:12:26]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=4158" target="_blank"&gt;测试驱动开发(TDD)跟敏捷开发有冲突&lt;/a&gt; [2011-08-14 16:04:38]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=4013" target="_blank"&gt;12款很棒的浏览器兼容性测试工具推荐&lt;/a&gt; [2011-07-18 12:19:22]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=3959" target="_blank"&gt;给Apache做压力测试时遇到的问题&lt;/a&gt; [2011-07-06 23:44:05]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=3749" target="_blank"&gt;如何快速解除用户防备？――浅谈可用性测试中沟通的技巧&lt;/a&gt; [2011-06-02 22:41:30]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=3733" target="_blank"&gt;使用gcov完成代码覆盖率的测试&lt;/a&gt; [2011-06-02 13:31:39]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=3685" target="_blank"&gt;使用windows7的virtual PC打造原装IE6、IE7、IE8测试环境&lt;/a&gt; [2011-06-01 23:34:50]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=3654" target="_blank"&gt;Super Smack&lt;/a&gt; [2011-05-30 13:52:59]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=3557" target="_blank"&gt;你真正需要的代码测试覆盖率是多少？&lt;/a&gt; [2011-04-28 13:39:03]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=3364" target="_blank"&gt;淘宝霜波说测试（一）&lt;/a&gt; [2011-03-01 22:42:42]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=3083" target="_blank"&gt;简单快速的可用性测试&lt;/a&gt; [2011-01-25 22:32:27]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=3002" target="_blank"&gt;详解黑盒、白盒、灰盒测试&lt;/a&gt; [2011-01-12 23:15:29]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=2945" target="_blank"&gt;在 Linux 的应用中测试中的延时和丢包模拟&lt;/a&gt; [2010-12-30 22:46:10]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=2893" target="_blank"&gt;node.js调研与服务性能测试&lt;/a&gt; [2010-12-21 23:10:28]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=2804" target="_blank"&gt;不用设置host，访问测试的http接口&lt;/a&gt; [2010-12-07 02:40:41]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=2745" target="_blank"&gt;Hadoop现有测试框架探幽&lt;/a&gt; [2010-11-24 23:01:46]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=2669" target="_blank"&gt;Latch free竞争 - 最近的SAP测试项目小记&lt;/a&gt; [2010-11-10 02:17:26]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=2634" target="_blank"&gt;【社会化设计】自我（self）部分――邀请测试版本（private beta）&lt;/a&gt; [2010-11-01 20:00:55]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=2538" target="_blank"&gt;兼顾安全及易用性的远程测试系统之搭建&lt;/a&gt; [2010-10-21 08:50:28]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=2428" target="_blank"&gt;在线测试不同操作系统不同浏览器网页的显示效果&lt;/a&gt; [2010-09-27 08:51:02]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=2414" target="_blank"&gt;A/B测试：实现方法&lt;/a&gt; [2010-09-26 22:23:45]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=2377" target="_blank"&gt;A/B测试：基本概念&lt;/a&gt; [2010-09-12 23:37:09]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=2372" target="_blank"&gt;软件测试工程师的职业素质&lt;/a&gt; [2010-09-09 22:06:23]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=2370" target="_blank"&gt;什么样的测试用例是好的&lt;/a&gt; [2010-09-09 22:04:42]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=2005" target="_blank"&gt;Xvfb+YSlow+ShowSlow搭建前端性能测试框架&lt;/a&gt; [2010-07-20 09:55:44]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=1914" target="_blank"&gt;WEB性能测试工具推荐&lt;/a&gt; [2010-07-12 23:27:11]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=1853" target="_blank"&gt;压力测试软件 Siege 的正确用法&lt;/a&gt; [2010-06-25 12:19:51]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=1794" target="_blank"&gt;apache下ab网站压力测试命令的参数、输出结果的中文注解&lt;/a&gt; [2010-06-17 10:15:05]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=1440" target="_blank"&gt;服务器性能测试工具推荐&lt;/a&gt; [2010-04-23 10:27:07]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=1371" target="_blank"&gt;自动化测试中Python与C/C++的混合使用&lt;/a&gt; [2010-04-14 13:31:21]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=1222" target="_blank"&gt;MySQL不同分支版本的压力测试&lt;/a&gt; [2010-03-18 09:02:29]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=936" target="_blank"&gt;自动化测试之惑&lt;/a&gt; [2010-01-07 13:29:01]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=797" target="_blank"&gt;Btrfs 测试结果简述&lt;/a&gt; [2009-12-10 13:43:43]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=787" target="_blank"&gt;如何当好测试组长(1)-制定测试计划&lt;/a&gt; [2009-12-08 23:10:19]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=623" target="_blank"&gt;性能测试工具sysbench简介&lt;/a&gt; [2009-11-18 09:29:55]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=349" target="_blank"&gt;mysql基本连接,mysqli,pdo,adodb,pearDB之间的区别，速度测试&lt;/a&gt; [2009-10-28 22:41:37]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=323" target="_blank"&gt;在生产环境中使用php性能测试工具xhprof&lt;/a&gt; [2009-10-27 08:58:40]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=91" target="_blank"&gt;在linux下常用的硬件测试软件&lt;/a&gt; [2009-10-12 09:13:03]&lt;/li&gt;&lt;/ol&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/MAyQ8bXqeRPpUpD5alRiC4xYI1Y/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/MAyQ8bXqeRPpUpD5alRiC4xYI1Y/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/MAyQ8bXqeRPpUpD5alRiC4xYI1Y/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/MAyQ8bXqeRPpUpD5alRiC4xYI1Y/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/blogreadIT/~4/iufb9wC6yDc" height="1" width="1"/&gt;</description>
		<content><![CDATA[1. 反映真实需求 这里存在先写测试和后写测试的区别。 先说后写测试。根据很多经验，在直接写产品实现代码时，需要考虑需求，同时需要兼顾实现的细节，用什么算法和语法。在对需求和考虑和实现细节间来回，很容易让人产生对其中一方的疏忽，遗漏掉一些需求方面，甚至在实现上存在缺陷。 有人会说我可以通过后写测试来保证。第一经验是，很多人都不会在实现完成后，补充测试，因为还有更多的工作和需求需要实现。第二是开发人员很容易在后补的测试中，只是试图去测试他已有的实现，而不是需求本身，很容易遗漏掉一些边界检查之类，在测试时，已有的实现细节会在脑子里面先入为主，即使实现存在问题或有漏洞，也很难在后补的测试中测出来。我阅读过很多面试者的测试代码，很明显都是后补的，因为一些很明显的问题没有测出来，甚至已经实现的逻辑也是只测试了一部分。而这些面试者都承认。 ]]></content>
	<feedburner:origLink>http://blogread.cn/it/article.php?id=5405</feedburner:origLink></item>
	<item>
		<title>使用exp/imp 导入11g数据到9i</title>
		<link>http://feedproxy.google.com/~r/blogreadIT/~3/LTBLR35mzQs/article.php</link>
		<author>惜分飞</author>
		<pubDate>2012-05-28 13:21:29</pubDate>
		<category domain="http://blogread.cn/it/category.php?id=4">Oracle</category>
		<guid isPermaLink="false">http://blogread.cn/it/article.php?id=5404</guid>
		<comments>http://blogread.cn/it/article.php?id=5404#comment</comments>
		<description>&lt;p&gt;&lt;strong&gt;标签：&lt;/strong&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://blogread.cn/it/tags.php?tag=exp" target="_blank"&gt;exp&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://blogread.cn/it/tags.php?tag=imp" target="_blank"&gt;imp&lt;/a&gt;&lt;/p&gt;&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;现在有个需求,需要使用exp/imp导入11g的数据库数据到9i中,解决这个问题一般来说想到三种方法思路,一个个尝试(其实从高版本服务端支持低版本客户端的原则,可以大概的猜测出使用9i的客户端处理该问题)&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;STRONG&gt;方法1:导出导入都使用11g客户端&lt;/STRONG&gt;&lt;/P&gt;&lt;PRE class="brush: bash; title: ; notranslate"&gt;--11g客户端导出
[oracle@xifenfei ~]$ exp chf/xifenfei file=/tmp/t_xifenfei.dmp
&amp;gt;log=/tmp/t_xifenfei.log tables=chf.t_xifenfei

Export: Release 11.2.0.3.0 - Production on Fri May 18 18:15:18 2012

Copyright (c) 1982, 2011, Oracle and/or its affiliates.  All rights reserved.

Connected to: Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
Export done in ZHS16GBK character set and AL16UTF16 NCHAR character set
server uses AL32UTF8 character set (possible charset conversion)

About to export specified tables via Conventional Path ...
. . exporting table                     T_XIFENFEI          2 rows exported
Export terminated successfully without warnings.

--11g客户端导入
[oracle@xifenfei ~]$ imp chf/xifenfei@ora9i file=/tmp/t_xifenfei_11g.dmp
&amp;gt;log=/tmp/t_xifenfei.log tables=chf.t_xifenfei

Import: Release 11.2.0.3.0 - Production on Fri May 18 18:17:24 2012

Copyright (c) 1982, 2011, Oracle and/or its affiliates.  All rights reserved.

IMP-00058: ORACLE error 6550 encountered
ORA-06550: line 1, column 33:
PLS-00302: component \'SET_NO_OUTLINES\' must be declared
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored
IMP-00000: Import terminated unsuccessfully
&lt;/PRE&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;这个错误是版本不兼容导致:PLS-00302: component ‘SET_NO_OUTLINES’ must be declared&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;STRONG&gt;方法2:11g客户端导出,9i客户端导入&lt;/STRONG&gt;&lt;/P&gt;&lt;PRE class="brush: bash; title: ; notranslate"&gt;--11g客户端导出
[oracle@xifenfei ~]$ exp chf/xifenfei file=/tmp/t_xifenfei.dmp
&amp;gt;log=/tmp/t_xifenfei.log tables=chf.t_xifenfei

Export: Release 11.2.0.3.0 - Production on Fri May 18 18:15:18 2012

Copyright (c) 1982, 2011, Oracle and/or its affiliates.  All rights reserved.

Connected to: Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
Export done in ZHS16GBK character set and AL16UTF16 NCHAR character set
server uses AL32UTF8 character set (possible charset conversion)

About to export specified tables via Conventional Path ...
. . exporting table                     T_XIFENFEI          2 rows exported
Export terminated successfully without warnings.

--传输到9i
[oracle@xifenfei tmp]$ scp t_xifenfei.dmp 192.168.1.10:/tmp/
The authenticity of host \'192.168.1.10 (192.168.1.10)\' can\'t be established.
RSA key fingerprint is 3d:0c:d1:4b:45:bd:a3:f5:25:eb:4d:52:d2:32:03:69.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added \'192.168.1.10\' (RSA) to the list of known hosts.
oracle@192.168.1.10\'s password:
t_xifenfei.dmp                          100%   56KB  56.0KB/s   00:00    

--9i客户端导入
[oracle@xifenfei ~]$ imp chf/xifenfei file=/tmp/t_xifenfei.dmp tables=t_xifenfei

Import: Release 9.2.0.4.0 - Production on Thu May 24 23:32:18 2012

Copyright (c) 1982, 2002, Oracle Corporation.  All rights reserved.

Connected to: Oracle9i Enterprise Edition Release 9.2.0.4.0 - Production
With the Partitioning, OLAP and Oracle Data Mining options
JServer Release 9.2.0.4.0 - Production

IMP-00010: not a valid export file, header failed verification
IMP-00000: Import terminated unsuccessfully
--版本不兼容(高版本的dump文件低版本不能识别)
&lt;/PRE&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;STRONG&gt;方法3:9i客户端导出,9i客户端导入&lt;/STRONG&gt;&lt;/P&gt;&lt;PRE class="brush: sql; title: ; notranslate"&gt;--9i客户端导出
[oracle@xifenfei ~]$ exp chf/xifenfei@ora11g file=/tmp/t_xifenfei_11g.dmp
&amp;gt;log=/tmp/t_xifenfei.log tables=chf.t_xifenfei

Export: Release 9.2.0.4.0 - Production on Thu May 24 23:37:20 2012

Copyright (c) 1982, 2002, Oracle Corporation.  All rights reserved.

Connected to: Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
Export done in ZHS16GBK character set and AL16UTF16 NCHAR character set
server uses AL32UTF8 character set (possible charset conversion)

About to export specified tables via Conventional Path ...
. . exporting table                     T_XIFENFEI          2 rows exported
Export terminated successfully without warnings.

--9i客户端导入
[oracle@xifenfei log]$ imp chf/xifenfei file=/tmp/t_xifenfei_11g.dmp log=/tmp/xifenfei.log full=y

Import: Release 9.2.0.4.0 - Production on Fri May 25 03:22:14 2012

Copyright (c) 1982, 2002, Oracle Corporation.  All rights reserved.

Connected to: Oracle9i Enterprise Edition Release 9.2.0.4.0 - Production
With the Partitioning, OLAP and Oracle Data Mining options
JServer Release 9.2.0.4.0 - Production

Export file created by EXPORT:V09.02.00 via conventional path
import done in ZHS16GBK character set and AL16UTF16 NCHAR character setSegmentation fault
--导入数据遇到setSegmentation fault异常终止
&lt;/PRE&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;STRONG&gt;解决setSegmentation fault异常终止&lt;/STRONG&gt;&lt;/P&gt;&lt;PRE class="brush: sql; title: ; notranslate"&gt;--1.修改exu9defpswitches视图
[oracle@xifenfei ~]$ sqlplus / as sysdba

SQL*Plus: Release 11.2.0.3.0 Production on Fri May 18 22:29:00 2012

Copyright (c) 1982, 2011, Oracle.  All rights reserved.

Connected to:
Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options

SQL&amp;gt; CREATE OR REPLACE VIEW exu9defpswitches (
  2                  compflgs, nlslensem ) AS
  3          SELECT  a.value, b.value
  4          FROM    sys.v$parameter a, sys.v$parameter b
  5          WHERE   a.name = \'plsql_code_type\' AND
  6                  b.name = \'nls_length_semantics\' ;

View created.

--2.9i导出11g数据
[oracle@xifenfei tmp]$ exp chf/xifenfei@ora11g file=/tmp/t_xifenfei_11g.dmp
&amp;gt;log=/tmp/xifenfei.log tables=t_xifenfei

Export: Release 9.2.0.4.0 - Production on Fri May 25 04:08:32 2012

Copyright (c) 1982, 2002, Oracle Corporation.  All rights reserved.

Connected to: Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
Export done in ZHS16GBK character set and AL16UTF16 NCHAR character set
server uses AL32UTF8 character set (possible charset conversion)

About to export specified tables via Conventional Path ...
. . exporting table                     T_XIFENFEI          2 rows exported
Export terminated successfully without warnings.

--9i导入数据
[oracle@xifenfei tmp]$ imp chf/xifenfei file=/tmp/t_xifenfei_11g.dmp
&amp;gt;log=/tmp/xifenfei.log tables=t_xifenfei

Import: Release 9.2.0.4.0 - Production on Fri May 25 04:08:53 2012

Copyright (c) 1982, 2002, Oracle Corporation.  All rights reserved.

Connected to: Oracle9i Enterprise Edition Release 9.2.0.4.0 - Production
With the Partitioning, OLAP and Oracle Data Mining options
JServer Release 9.2.0.4.0 - Production

Export file created by EXPORT:V09.02.00 via conventional path
import done in ZHS16GBK character set and AL16UTF16 NCHAR character set
. importing CHF\'s objects into CHF
. . importing table                   "T_XIFENFEI"          2 rows imported
Import terminated successfully without warnings.
--至此导入成功,完成了11gr2数据导入到9ir2中
&lt;/PRE&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;通过一系列的实验证明,需要把11g的数据导入到9i中,需要使用9i的客户端进行,其中exu9defpswitches视图需要重建,否则会出现setSegmentation fault异常,导致导入失败.&lt;/P&gt;
				&lt;p&gt;&lt;strong&gt;您可能还对下面的文章感兴趣：&lt;/strong&gt;&lt;/p&gt;
				&lt;p&gt;&lt;ol&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=1668" target="_blank"&gt;不可靠的EXP远程备份&lt;/a&gt; [2010-05-29 10:55:21]&lt;/li&gt;&lt;/ol&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/u71qrwZ1mV2Lf6sAQELL3gjtqcM/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/u71qrwZ1mV2Lf6sAQELL3gjtqcM/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/u71qrwZ1mV2Lf6sAQELL3gjtqcM/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/u71qrwZ1mV2Lf6sAQELL3gjtqcM/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/blogreadIT/~4/LTBLR35mzQs" height="1" width="1"/&gt;</description>
		<content><![CDATA[现在有个需求,需要使用exp/imp导入11g的数据库数据到9i中,解决这个问题一般来说想到三种方法思路,一个个尝试(其实从高版本服务端支持低版本客户端的原则,可以大概的猜测出使用9i的客户端处理该问题) 方法1:导出导入都使用11g客户端 这个错误是版本不兼容导致:PLS-00302: component ‘SET_NO_OUTLINES’ must be declared 方法2:11g客户端导出,9i客户端导入 方法3:9i客户端导出,9i客户端导入 解决setSegmentation fault异常终止 通过一系列的实验证明,需要把11g的数据导入到9i中,需要使用9i的客户端进行,其中exu9defpswitches视图需要重建,否则会出现setSegmentation fault异常,导致导入失败. ]]></content>
	<feedburner:origLink>http://blogread.cn/it/article.php?id=5404</feedburner:origLink></item>
	<item>
		<title>构造函数沉思录</title>
		<link>http://feedproxy.google.com/~r/blogreadIT/~3/HS8BDrV0Qx4/article.php</link>
		<author>dreamhead</author>
		<pubDate>2012-05-28 13:21:05</pubDate>
		<category domain="http://blogread.cn/it/category.php?id=9">算法</category>
		<guid isPermaLink="false">http://blogread.cn/it/article.php?id=5403</guid>
		<comments>http://blogread.cn/it/article.php?id=5403#comment</comments>
		<description>&lt;p&gt;&lt;strong&gt;标签：&lt;/strong&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://blogread.cn/it/tags.php?tag=%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0" target="_blank"&gt;构造函数&lt;/a&gt;&lt;/p&gt;&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;STRONG&gt;缘起&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;构造函数，是由C++引入主流程序世界的，其用意是在《C++语言的设计与演化》如是表达：&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;它建立起其它成员函数进行操作的环境基础。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;在很早的一篇blog《&lt;A href="http://dreamhead.blogbus.com/logs/456837.html" target=_blank&gt;对象的声明&lt;/A&gt;》中，我曾探讨过构造函数的来龙去脉。对于面向对语言而言，构造函数似乎是标配。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;一个语言特性，一旦被扔到真实世界，随之而来的是，其使用往往会超出其设计者的初衷，构造函数亦是如此。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;事实上，通过前面C++之父的描述，我们依然很难定位构造函数的准确用法。所以，我们常常看到许多人把诸多操作强塞入构造函数，造成构造函数极为复杂，进而关于导致了一些复杂的语法讨论，比如如何处理构造函数抛出的异常。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;这里要讨论的是构造函数的另一个常见问题。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;STRONG&gt;重载构造函数&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;同样是在《C++语言的设计与演化》里，有这样一段描述：&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; 观察发现，允许定义多个构造函数很有价值，因此这也就成了C++重载机制的一个重要应用方面。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;是的，我要说的就是构造函数重载。构造函数可以重载，Java和C#也拿了过来，这似乎成了一种约定俗成。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;在实际应用中，有不少人会这么做：给一个类创建多个构造函数，有的初始化了全部的字段/成员变量，有的只初始化诸多字段/成员变量中的几个。下面便是一个例子：&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public Image(URL url, Tag tag) {&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; this.url = url;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; this.tag = tag;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public Image(URL url) {&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; this.url = url;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;这么做的原因通常是，初写这些代码时，这些构造函数要用在不同的场合下。比如，在产品代码中，我们需要的可能是一个完整的对象，而在测试代码中，针对要测试的内容，我们只要设置几个字段即可。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;但是，因为它们都是构造函数，名字完全一致，其最初的意图无法体现，后来的人看到这样的函数，图省事，便拿过来用。随后一些初始化不完整的对象就出现在系统中。随着系统的不断演进，残缺的对象在很多情况下就会出问题，于是，为了修补，我们再向代码里添加一些setter。与setter相伴的往往是，可变(mutable)对象的出现。而许多系统的状态不稳定就是由各种可变对象造成(这也是一个值得讨论的话题)。貌似很简单的构造函数蕴含着诸多的问题。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;就这个问题而言，可以怎样解决呢？&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;一种常见的解决方案是，类只提供一个完整的构造函数，至于其它部分，则采用工厂方法完成。比如上面的例子，对Image类，我们只有一个构造函数：&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public Image(URL url, Tag tag) {&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; this.url = url;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; this.tag = tag;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;如果在测试里用到，就为它创建一个工厂方法：&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; class ImageForTestFactory {&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; public static Image createImageWithURL(URL url) {&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; return new Image(url, null);&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; }&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Image的第二个参数Tag，这里就简单的设置为null，事实上，我们可以根据需要进行设置。比如，我们需要所有的字段都不能为空，这里就可以提供一个缺省的Tag。这段代码的使用者根本无需顾及Tag究竟是怎样。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;工厂方法很大的一个价值，便在于它提供了名字，表明意图。名字到底有多大价值，如果你对整洁代码(Clean Code)有所追求，便就会发现，关于整洁代码的讨论，第一个要讨论的东西便是命名。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;事实上，这些做法并不如何特殊，&lt;A href="http://book.douban.com/subject/3360807/" target=_blank&gt;《Effective Java》第二版&lt;/A&gt;，开篇讨论的就是这样的问题。条款1就是“考虑以静态工厂方法代替构造函数”。这个条款里面建议的方案更加激进，建议将构造函数设置为private。这样一来，人们就完全没有机会使用该类的构造函数，只能通过其提供的工厂方法构造对象：&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; class Image {&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; private Image(URL url, Tag tag) {&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; this.url = url;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; this.tag = tag;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; }&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; public static Image createNewImage(URL url, Tag tag) {&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; return new Image(url, null);&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; }&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; ...&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;另外一种值得考虑的做法是，采用builder模式。《Effective Java》第二版的条款2给出了更详细的解释。所以，&lt;STRONG&gt;如果类里有多于一个的构造函数，那么请考虑其它方式代替。&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;STRONG&gt;无构造函数的Go&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;顺着这个思路，再进一步，我们完全可以写出“除本类之外，没有new本类对象的代码”。换句话说，如果不是语言层面有所限制，我们完全可以抛弃构造函数，而事实上，Go语言就这么做了。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;在Go语言里，如果我们要构造一个对象可以这么做：&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; type Person struct {&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; name string&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; func NewPerson(name string)(*Person) {&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; p := new(Person)&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; p.name = name&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; return p&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;在语法上，Go语言本身并没有类，但从C/C++的年代我们就知道，struct和class本质是一样的。所以，实际上，NewPerson就是一个构造函数，它负责初始化了Person的相关字段。构造一个对象的方法就可以这样：&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; p := NewPerson("dreamhead")&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;从本质上说，NewPerson就是一个工厂方法。当然，Go语言之所以可以这么做，因为其struct的所有字段都是public，可以自由访问，在面向对象程序设计语言中，恐怕没那么简单。或许，抛开构造函数的做法，让我们一下子回归到了最初的年代，但同之前模糊的印象不同，如今我们对构造的概念有了全新的理解。我们依然要构造对象，只是不再依赖于构造函数而已。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;是时候反思一下构造函数了。C++设计于80年代，那时候，设计模式还不是主流，那时候，编写代码更多强调的是功能，而非整洁。&lt;/P&gt;
				&lt;p&gt;&lt;strong&gt;您可能还对下面的文章感兴趣：&lt;/strong&gt;&lt;/p&gt;
				&lt;p&gt;很抱歉，暂时没有...... &lt;/p&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/1zfFbIj32cW4wImLo6iBCNPgWSc/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/1zfFbIj32cW4wImLo6iBCNPgWSc/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/1zfFbIj32cW4wImLo6iBCNPgWSc/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/1zfFbIj32cW4wImLo6iBCNPgWSc/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/blogreadIT/~4/HS8BDrV0Qx4" height="1" width="1"/&gt;</description>
		<content><![CDATA[缘起构造函数，是由C++引入主流程序世界的，其用意是在《C++语言的设计与演化》如是表达： 它建立起其它成员函数进行操作的环境基础。在很早的一篇blog《对象的声明》中，我曾探讨过构造函数的来龙去脉。对于面向对语言而言，构造函数似乎是标配。一个语言特性，一旦被扔到真实世界，随之而来的是，其使用往往会超出其设计者的初衷，构造函数亦是如此。事实上，通过前面C++之父的描述，我们依然很难定位构造函数的准确用法。所以，我们常常看到许多人把诸多操作强塞入构造函数，造成构造函数极为复杂，进而关于导致了一些复杂的语法讨论，比如如何处理构造函数抛出的异常。这里要讨论的是构造函数的另一个常见问题。重载构造函数同样是在《C++语言的设计与演化》里，有这样一段描述： 观察发现，允许定义多个构造函数很有价值，因此这也就成了C++重载机制的一个重要应用方面。是的，我要说的就是构造函数重载。]]></content>
	<feedburner:origLink>http://blogread.cn/it/article.php?id=5403</feedburner:origLink></item>
	<item>
		<title>Django的静态文件服务 总结</title>
		<link>http://feedproxy.google.com/~r/blogreadIT/~3/v3fyoTkescs/article.php</link>
		<author>Falcon</author>
		<pubDate>2012-05-28 13:20:39</pubDate>
		<category domain="http://blogread.cn/it/category.php?id=18">系统运维</category>
		<guid isPermaLink="false">http://blogread.cn/it/article.php?id=5402</guid>
		<comments>http://blogread.cn/it/article.php?id=5402#comment</comments>
		<description>&lt;p&gt;&lt;strong&gt;标签：&lt;/strong&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://blogread.cn/it/tags.php?tag=Django" target="_blank"&gt;Django&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://blogread.cn/it/tags.php?tag=%E9%9D%99%E6%80%81%E6%96%87%E4%BB%B6" target="_blank"&gt;静态文件&lt;/a&gt;&lt;/p&gt;&lt;P&gt;安装&lt;BR&gt;===============================================&lt;BR&gt;在django1.3+，内置了stataic 模块,只需要在INSTALL_APPS里注释掉相关代码即可，对于1.3以下版本可以使用pip install django-staticfiles ，并把staticfiles添加到INSTALL_APP&lt;/P&gt;
&lt;P&gt;配置&lt;BR&gt;===============================================&lt;BR&gt;在settings.py内配置相关变量，&lt;BR&gt;MEDIA前缀表示保存用户上传的文件夹&lt;BR&gt;STATIC前缀表示应用使用到的静态文件的所在文件夹，默认放在应用的static目录下，&lt;BR&gt;如果需要增加静态文件夹，可以使用STATICFILES_DIRS = (‘/another_dir/’,) 元组进行配置&lt;/P&gt;
&lt;P&gt;MEDIA_ROOT = ‘/home/dotcloud/data/media/’&lt;BR&gt;MEDIA_URL = ‘/media/’&lt;/P&gt;
&lt;P&gt;STATIC_ROOT = ‘/home/dotcloud/data/static/’&lt;BR&gt;STATIC_URL = ‘/static/’&lt;BR&gt;ADMIN_MEDIA_PREFIX = ‘/static/admin/’&lt;/P&gt;
&lt;P&gt;在开发时查看MEDIA目录内容&lt;BR&gt;===============================================&lt;BR&gt;可向urls.py追加以下内容::&lt;/P&gt;
&lt;P&gt;from hello import settings&lt;BR&gt;if settings.DEBUG == True:&lt;BR&gt;urlpatterns += patterns(”,&lt;BR&gt;(r’^media/(?P&amp;lt;path&amp;gt;.*)$’, ‘django.views.static.serve’,&lt;BR&gt;{‘document_root’: settings.MEDIA_ROOT}),&lt;BR&gt;)&lt;/P&gt;
&lt;P&gt;在生产环境下转移各应用 的静态static目录下的内容，由服务器进行静态文件处理&lt;BR&gt;可执行以下命令::&lt;/P&gt;
&lt;P&gt;$manage.py collectstatic -noinput&lt;/P&gt;
&lt;P&gt;PS,本人认为media目录应该在服务器配置访问权限。&lt;/P&gt;
&lt;P&gt;模板使用&lt;BR&gt;===============================================&lt;/P&gt;
&lt;P&gt;`django官方文档`_&amp;nbsp; 提到需要配置 TEMPLATE_CONTEXT_PROCESSORS&lt;BR&gt;然后在 模板中这样应用 ::&lt;/P&gt;
&lt;P&gt;&amp;lt;img src=”{{ STATIC_URL }}images/hi.jpg” /&amp;gt;&lt;/P&gt;
&lt;P&gt;或者使用模板tag::&lt;/P&gt;
&lt;P&gt;{% load static %}&lt;BR&gt;&amp;lt;img src=”{% get_static_prefix %}images/hi.jpg” /&amp;gt;&lt;/P&gt;
&lt;P&gt;处理多个静态文件时可以进一步简化为::&lt;BR&gt;{% load static %}&lt;BR&gt;{% get_static_prefix as STATIC_PREFIX %}&lt;/P&gt;
&lt;P&gt;&amp;lt;img src=”{{ STATIC_PREFIX }}images/hi.jpg” /&amp;gt;&lt;BR&gt;&amp;lt;img src=”{{ STATIC_PREFIX }}images/hi2.jpg” /&amp;gt;&lt;/P&gt;
&lt;P&gt;.. note::&lt;/P&gt;
&lt;P&gt;我在django1.2下按上面的说明配置无法取得static_url,参考资料修改如下方可。&lt;/P&gt;
&lt;P&gt;setttings.py追加入以下代码::&lt;/P&gt;
&lt;P&gt;TEMPLATE_CONTEXT_PROCESSORS = (&lt;BR&gt;‘django.core.context_processors.debug’,&lt;BR&gt;‘django.core.context_processors.i18n’,&lt;BR&gt;‘django.core.context_processors.media’,&lt;BR&gt;#’django.core.context_processors.static’,&lt;BR&gt;‘staticfiles.context_processors.static’, #此处为手动安装staticfiles的写法&lt;BR&gt;‘django.contrib.auth.context_processors.auth’,&lt;BR&gt;‘django.contrib.messages.context_processors.messages’,&lt;BR&gt;)&lt;/P&gt;
&lt;P&gt;views.py::&lt;/P&gt;
&lt;P&gt;from django.template import RequestContext&lt;/P&gt;
&lt;P&gt;def index(request):&lt;/P&gt;
&lt;P&gt;return render_to_response(‘index.html’,{},context_instance=RequestContext(request))&lt;/P&gt;
&lt;P&gt;此后模板页可以使用 **{{ STATIC_URL }}** 变量&lt;/P&gt;
&lt;P&gt;.. _django官方文档: https://docs.djangoproject.com/en/1.3/howto/static-files/&amp;lt;/path&amp;gt;&lt;/P&gt;
				&lt;p&gt;&lt;strong&gt;您可能还对下面的文章感兴趣：&lt;/strong&gt;&lt;/p&gt;
				&lt;p&gt;&lt;ol&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=4188" target="_blank"&gt;应用中的静态文件&lt;/a&gt; [2011-08-19 23:10:33]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=2143" target="_blank"&gt;当使用 Nginx 做 Hash 时对动态文件和静态文件的处理&lt;/a&gt; [2010-08-02 22:59:10]&lt;/li&gt;&lt;/ol&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/OtWtL95BrgNAIPyGLtcTC6L8ngg/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/OtWtL95BrgNAIPyGLtcTC6L8ngg/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/OtWtL95BrgNAIPyGLtcTC6L8ngg/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/OtWtL95BrgNAIPyGLtcTC6L8ngg/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/blogreadIT/~4/v3fyoTkescs" height="1" width="1"/&gt;</description>
		<content><![CDATA[在django1.3+，内置了stataic 模块,只需要在INSTALL_APPS里注释掉相关代码即可，对于1.3以下版本可以使用pip install django-staticfiles ，并把staticfiles添加到INSTALL_APP 配置 ...]]></content>
	<feedburner:origLink>http://blogread.cn/it/article.php?id=5402</feedburner:origLink></item>
	<item>
		<title>走进工具型网站——释义及典型案例</title>
		<link>http://feedproxy.google.com/~r/blogreadIT/~3/1qeI0SKu5RM/article.php</link>
		<author>CDCer</author>
		<pubDate>2012-05-28 13:19:34</pubDate>
		<category domain="http://blogread.cn/it/category.php?id=21">设计思想</category>
		<guid isPermaLink="false">http://blogread.cn/it/article.php?id=5401</guid>
		<comments>http://blogread.cn/it/article.php?id=5401#comment</comments>
		<description>&lt;p&gt;&lt;strong&gt;标签：&lt;/strong&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://blogread.cn/it/tags.php?tag=%E5%B7%A5%E5%85%B7%E5%9E%8B" target="_blank"&gt;工具型&lt;/a&gt;&lt;/p&gt;&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;A href="http://cdc.tencent.com/?p=5631" target=_blank&gt;&lt;IMG src="http://cdc.tencent.com/wp-content/uploads/2012/05/15.jpg"&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;　　提到工具型网站，我们首先会有个疑问：大千网络网站众生，究竟什么样的网站才算是工具型网站？它的特征是什么，与其他网站有什么不同？&amp;nbsp;从网上搜索相关信息，了解到关于该名词的具体解释并没有明确的说法。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;　　为了方便后续的研究，在此先结合之前同学们的研究成果，综合整理一下，提供工具型网站的定义版本，供参考：&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;STRONG&gt;　　——所谓工具型网站，顾名思义就是构筑在互联网上的工具，是指为帮助人们完成某一特定领域的目标需求而提供的、具有一定操作流程、以完成该目标任务为主要目的、基于网络应用的工具手段。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/STRONG&gt;　　它的主要特征在于：&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 　　-&amp;nbsp;以完成一项或多项任务为目的&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 　　-&amp;nbsp;注重操作流程引导&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 　　-&amp;nbsp;强调快速完成任务&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 　　-&amp;nbsp;非完成目标的唯一手段，只是协助用户更高效完成该目标&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;　　同时，很多工具型网站还特别配备一个独立门户，该门户以信息展现为主，用来专门介绍工具的价值、动态等，并提供登录或下载入口。由于这种门户与工具页指向的高度一体性，我们也将它归纳到工具型网站的范畴中来，称之为&lt;STRONG&gt;工具型网站门户&lt;/STRONG&gt;(或工具性网站首页)。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;　　为了帮助我们对工具型网站形成更直观的概念，可以根据网站功能将网站区分为内容型网站和工具型网站。关于工具型网站与内容型网站的对比区别，已有同学作了较详细的阐述(如想进一步了解可&lt;A href="http://blog.sina.com.cn/s/blog_453d02200100ruez.html" target=_blank&gt;查看相关文章&lt;/A&gt;)，在此不赘述。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;　　典型的工具性网站有：Google系列(搜索、翻译、文档、阅读器…)、财付通、支付宝、数据魔方、salesforce、xero、TA、DNSpod等；&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;　　典型的内容型网站有：Sina、腾讯网、天涯论坛等。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;　　下面就从体验角度，介绍几个我比较喜欢的工具型网站典型案例。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;STRONG&gt;&lt;/STRONG&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;STRONG&gt;&lt;A href="http://www.google.com/" target=_blank&gt;Google&lt;/A&gt;&lt;/STRONG&gt;&lt;STRONG&gt;——一致系王道&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;　　工具型网站，应用最广泛的应该是我们非常熟悉的google系列产品了，如google搜索、翻译、文档等等，大部分都是随着google搜索后逐渐推出的新工具。这些工具给网民的互联网生活提供了极大的便利。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;　　料想如此多的产品线，会很容易因为功能属性的差异而产生不同的视觉风格。但是我们却看到google在多产品体系下的视觉风格，无论导航条、色彩体系、基本布局结构等方面都非常统一，如所有背景层都是黑白灰色系、所有的新建功能都是醒目红按钮、所有功能菜单都居左等。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;　　这种一致性极大减少了用户对新产品的认知、学习成本，达到自来熟的境界~体现了google体验团队在品牌形象和体验规范方面强大的制定、执行能力~&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;IMG class="aligncenter size-full wp-image-5632" alt="" src="http://cdc.tencent.com/wp-content/uploads/2012/05/2.png" width=720 height=1500&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;STRONG&gt;&lt;/STRONG&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;STRONG&gt;&lt;/STRONG&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;STRONG&gt;&lt;A href="http://www.xero.com/" target=_blank&gt;Xero&lt;/A&gt;&lt;/STRONG&gt;&lt;STRONG&gt;——小清新却很实用&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;　　下面这个Xero，是一个典型的小清新，我对它的喜爱，来自它的简洁而不简单，美丽却不喧哗，非常符合该网站的功能定位。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;　　Xero是一个功能比较全面的针对小型企业的记账工具，产出包括现金簿，总账，发票和报告。作为一个记账类工具网站，用户最关心的诉求当然是安全、准确，所以Xero非常敏锐的在门户和产品页中统一使用了中亮度蓝+绿色来表达，同时配图、结构上横平竖直，四平八稳，将安全、可信赖的氛围营造到极致。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;　　在信息展示方面，Xero门户中具有web2.0的典型特征，比如大量留白、大小字体的对比应用等；而在产品页中，则将各控件元素视觉尽量作减法，例如，表格不要纵线框、chart图色彩统一、按钮质感简化统一、所有的可点击文字包括普链表头页签等全部统一为蓝色、等等，做这些的目的，就是为了让大量的文字数据信息不被多余的细节干扰，让主题一目了然，帮助用户在干净、舒畅的环境中快速完成任务。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;　　该产品曾被Nielsen Norman Group列入10 Best Application Uis。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;IMG class="aligncenter size-full wp-image-5633" alt="" src="http://cdc.tencent.com/wp-content/uploads/2012/05/3.png" width=720 height=1407&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;STRONG&gt;&lt;A href="http://www.fork-cms.com/" target=_blank&gt;Fork&lt;/A&gt;&lt;/STRONG&gt;&lt;STRONG&gt;——配图创意为品牌形象加分&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;　　作为工具型网站，工具本身带给用户的价值固然能决定网站的成败，但门户亦像是产品的橱窗，吸引访客快速了解产品的用途、价值，并进而使用。因此门户的成功与否，也对网站有着重要的影响。如何在色彩、布局、或配图方面发挥创意，让门户尽量吸引眼球，获得访客的青睐，是视觉设计师们的一大课题。而下面的Ford，在配图创意方面算是一个典型，它显著的情景式设计的特点，让人眼前一亮。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;　　提到招行人们会想到向日葵，提到腾讯人们会想到企鹅，提到Mailchimp人们会想到邮递员monkey，现在提到Fork，人们应该会想到这位可爱的坐在小船上拿叉的老渔夫了。也许它的logo不起眼，但是有了这个代言人的衬托，这个工具，实在让人难忘了。如果你再仔细翻看一下，会发现在几个内页中，都有与这个大海主题相关联的插图设计。看到这些，即使你是一路人，会不会好奇到忍不住点download来用用？&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;　　值得一提的是，该门户页面框架上使用了流行的响应式web设计模式，在浏览器缩放、手机访问时均有版式微调，体现了视觉传达的完整性。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;IMG class="aligncenter size-full wp-image-5634" alt="" src="http://cdc.tencent.com/wp-content/uploads/2012/05/41.png" width=720 height=1013&gt;　　关于工具型网站门户的体验设计，小伊万同学对此有较深入的研究，&lt;A title=工具型网站首页的设计思考 href="http://cdc.tencent.com/?p=5220" target=_blank&gt;参考此处&lt;/A&gt;。&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;STRONG&gt;&lt;/STRONG&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;STRONG&gt;&lt;A href="http://wufoo.com/" target=_blank&gt;Wufoo&lt;/A&gt;&lt;/STRONG&gt;&lt;STRONG&gt;——体验创新源自对简单的追求&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;　　工具型网站，通常都有一些比较正式的用途，纵观此类网站觉得冷色调居多，因此初见Wufoo觉得非常特别，它大面积使用暖色系，圆角造型的弧度也偏大，看上去轻松随意。了解原因之前我们先了解下这个产品的用途和价值诉求。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;　　Wufoo主要用来创建网上表格、邀请和简单的订单付款，还可以发送邀请和管理日程。产品方对Wufoo的期望是：“Wufoo的主要功能是帮助任何人创建HTML表单，但最终我们力争成为在互联网上收集信息的最简单的方法。”&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;　　所以，用暖色系体现亲和力，降低用户使用门槛，让人感觉这是一个任何人都可以用的产品——你可以用来处理工作，也可以用来处理个人的事情。不仅是颜色方面，在整个网站任务流的交互框架设计方面也处处体现了这种简单易用的价值理念，如左右翻起的选项设置、新颖的表单字段添加方式、体贴的进入向导，的确是一个具有新颖体验的网站。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;　　该网站也被Nielsen Norman Group列入10 Best Application Uis。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;IMG class="aligncenter size-full wp-image-5635" alt="" src="http://cdc.tencent.com/wp-content/uploads/2012/05/5.png" width=720 height=1500&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;STRONG&gt;&lt;A href="https://www.tenpay.com/" target=_blank&gt;财付通&lt;/A&gt;—处处营造轻松氛围&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;　　第一次看到改版后的财付通，很为首页这张图所吸引。男女主轻轻偎依，把玩各自的手机，看上去开心、随意。如此贴近大众生活的幸福场景，是对广告语的绝佳诠释。与此同时，整个网站的风格，都给人简洁轻松感。事实上改版后的信息结构确实更舒适，重点更突出，流程更顺畅了。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;IMG class="aligncenter size-full wp-image-5636" alt="" src="http://cdc.tencent.com/wp-content/uploads/2012/05/62.jpg" width=720 height=1438&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;　　说到这里有没有发现，财付通的信息布局结构，与之前看到的几个案例有较大的区别？&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;　　前面案例的工具页面，界面元素以树、表格、各类控件为主，其布局结构比较接近应用程序；而财付通及，他们的元素结构以开放式为主，少了很多控件框架的限制，表格展现的形态更加灵活，引导说明文字信息较多，是接近网页布局的工具型网站典型。同类型的还有支付宝、腾讯安全中心、充值中心等。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;　　那么，都是工具型网站，为何元素布局应用会有如此大的差异呢？&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;　　简要来说，就是因为前者是从客户端的体验设计思维发展而来，而后者是基于早期网页的设计思维发展过来。一个简单的例子，在前者的信息提示方面，一般会较多趋向于弹出付出层的方式，而后者，则更趋向于在当前页面中给出信息提示指引。当然现在，二者之间正在互相影响，这种区别有了逐渐拉近的趋势。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;STRONG&gt;新技术新发展&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;　　后续，随着屏幕分辨率越来越大(据CNZZ统计数据2012年1月1024*768的占有率已下滑到28.8%，与第2位1440*900的21%差距已经越来越小，且呈多样化趋势)，网络速度越来越快，可以预见的是，这些网页新技术亦将会更多地为工具型网站所用，例如刚提到的响应式web设计，例如瀑布流、例如富媒体应用、例如大图片背景填充等等，后续也必将为我们的视觉设计打开新的思路，提供更多的创意提升空间。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;　　以上只是对工具型网站的初步分析，其实工具型网站在体验设计上亦可谓自成体系，还有更深入的研究学习空间，欢迎更多感兴趣的同学们来一起深入探讨。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(本文出自腾讯CDC博客: &lt;A href="http://cdc.tencent.com/?p=5631" target=_blank&gt;http://cdc.tencent.com/?p=5631&lt;/A&gt;)&lt;/P&gt;
				&lt;p&gt;&lt;strong&gt;您可能还对下面的文章感兴趣：&lt;/strong&gt;&lt;/p&gt;
				&lt;p&gt;&lt;ol&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=4985" target="_blank"&gt;工具型网站首页的设计思考&lt;/a&gt; [2012-02-26 23:34:32]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=3431" target="_blank"&gt;工具型产品的设计感想&lt;/a&gt; [2011-03-21 00:14:53]&lt;/li&gt;&lt;/ol&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/jPjubBCWSYnMoLWMPAJVQISXc_c/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/jPjubBCWSYnMoLWMPAJVQISXc_c/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/jPjubBCWSYnMoLWMPAJVQISXc_c/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/jPjubBCWSYnMoLWMPAJVQISXc_c/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/blogreadIT/~4/1qeI0SKu5RM" height="1" width="1"/&gt;</description>
		<content><![CDATA[　　提到工具型网站，我们首先会有个疑问：大千网络网站众生，究竟什么样的网站才算是工具型网站？它的特征是什么，与其他网站有什么不同？&nbsp;从网上搜索相关信息，了解到关于该名词的具体解释并没有明确的说法。 　　为了方便后续的研究，在此先结合之前同学们的研究成果，综合整理一下，提供工具型网站的定义版本，供参考： 　　——所谓工具型网站，顾名思义就是构筑在互联网上的工具，是指为帮助人们完成某一特定领域的目标需求而提供的、具有一定操作流程、以完成该目标任务为主要目的、基于网络应用的工具手段。 　　它的主要特征在于： 　　–&nbsp;以完成一项或多项任务为目的 　　–&nbsp;注重操作流程引导 　　–&nbsp;强调快速完成任务 　　–&nbsp;非完成目标的唯一手段，只是协助用户更高效完成该目标 　　同时，很多工具型网站还特别配备一个独立门户，该门户以信息展现为主，用来专门介绍工具的价值、动态等，并提供登录或下载入口。]]></content>
	<feedburner:origLink>http://blogread.cn/it/article.php?id=5401</feedburner:origLink></item>
	<item>
		<title>即时流式数据 MapReduce</title>
		<link>http://feedproxy.google.com/~r/blogreadIT/~3/tfv-wcrR8FA/article.php</link>
		<author>ideawu</author>
		<pubDate>2012-05-28 13:19:14</pubDate>
		<category domain="http://blogread.cn/it/category.php?id=17">系统架构</category>
		<guid isPermaLink="false">http://blogread.cn/it/article.php?id=5400</guid>
		<comments>http://blogread.cn/it/article.php?id=5400#comment</comments>
		<description>&lt;p&gt;&lt;strong&gt;标签：&lt;/strong&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://blogread.cn/it/tags.php?tag=MapReduce" target="_blank"&gt;MapReduce&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://blogread.cn/it/tags.php?tag=%E6%B5%81%E5%BC%8F%E6%95%B0%E6%8D%AE" target="_blank"&gt;流式数据&lt;/a&gt;&lt;/p&gt;&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;传统的 MapReduce 如 Hadoop, 是以任务的形式进行的 — 获取一批数据, 提交给系统, 然后获取结果. 但是, 有一些统计的需求是即时的, 统计任务需要持续的运行, 一旦数据生成, 便立即发给统计任务处理, 生成的结果”推”给接收者.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;以一个网站用户在线时长统计的需求为例子, 那么系统就有这几个部分:&lt;/P&gt;
&lt;H3&gt;数据接收&lt;/H3&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;接收 Web Server(如 Apache/Nginx) 的 log, 例如使用 syslog.&lt;/P&gt;
&lt;H3&gt;Mapper(格式转换)&lt;/H3&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;依次输入以行为单位的原始的 Apache log, 输出一条或者多条结构化的数据. 这个输出将出 Reducer 进行下一步处理.&lt;/P&gt;
&lt;H3&gt;Reducer(统计器)&lt;/H3&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;不同的精度用不同的统计器, 因为统计结果必须在要求的&lt;B&gt;精度&lt;/B&gt;时间内进行输出. 例如当精度要求是小时, 用户连续在线1个小时, 并且横跨在2个自然小时上, 那么, 统计结果应该是2条. 如果精度要求是天, 那么类似, 跨越自然天的数据应该被分割.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;当 Reducer 的&lt;B&gt;精度&lt;/B&gt;时间到达之后(如一个小时过完), Reducer 应该复位.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;传统 Reducer 的输入是来自 Mapper, 但 Reducer 的输入来源应该包括其它的 Reducer. 例如, 按小时统计的 Reducer 的输出可以作为按天统计的 Reducer 的输入.&lt;/P&gt;
&lt;H3&gt;结果分发器&lt;/H3&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;结果会以不同的形式发送出去, 如写成文件, 发邮件, 推送到其它系统…&lt;/P&gt;
&lt;H3&gt;结果的结构&lt;/H3&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;有一种简单的数据库存储结构(先不考虑分表分库), 表的结构为:&lt;/P&gt;&lt;PRE&gt;time, timespan, key, val
UNIQUE(time, key)
&lt;/PRE&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;用户在线时长的数据这样存:&lt;/P&gt;&lt;PRE&gt;2012-05-25 09:12:20, 小时, ip1, 100s // ip1在线了100s, 从09:12:20开始
2012-05-25 12:24:10, 小时, ip1, 200s // ip1在线了100s, 从09:12:20开始
2012-05-25 09:12:20, 小时, ip1, 300s // ip1 2012-05-25 在线了300s, 但不是连续在线时间
&lt;/PRE&gt;
&lt;H3&gt;系统&lt;/H3&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;根据上面的思想, 可以设计出一个即时流式数据的 MapReduce 系统, 也可以做一个代码框架. 但系统和框架的区别是, 系统包含了运行环境.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;上面不同部分之间的通信会形成一种广义上的”队列”, 所以需要进行队列管理.&lt;/P&gt;
				&lt;p&gt;&lt;strong&gt;您可能还对下面的文章感兴趣：&lt;/strong&gt;&lt;/p&gt;
				&lt;p&gt;&lt;ol&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=4920" target="_blank"&gt;《big data glossary》之MapReduce&lt;/a&gt; [2012-02-01 18:05:05]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=4094" target="_blank"&gt;使用 Perl 中的 Gearman来实现 MapReduce&lt;/a&gt; [2011-07-31 12:49:52]&lt;/li&gt;&lt;/ol&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/lmauXSeoG-mAS62JTN38wAOtL58/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/lmauXSeoG-mAS62JTN38wAOtL58/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/lmauXSeoG-mAS62JTN38wAOtL58/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/lmauXSeoG-mAS62JTN38wAOtL58/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/blogreadIT/~4/tfv-wcrR8FA" height="1" width="1"/&gt;</description>
		<content><![CDATA[传统的 MapReduce 如 Hadoop, 是以任务的形式进行的 — 获取一批数据, 提交给系统, 然后获取结果. 但是, 有一些统计的需求是即时的, 统计任务需要持续的运行, 一旦数据生成, 便立即发给统计任务处理, 生成的结果”推”给接收者. 以一个网站用户在线时长统计的需求为例子, 那么系统就有这几个部分: 数据接收接收 Web Server(如 Apache/Nginx) 的 log, 例如使用 syslog. Mapper(格式转换) 依次输入以行为单位的原始的 Apache log, 输出一条或者多条结构化的数据. 这个输出将出 Reducer 进行下一步处理. Reducer(统计器) 不同的精度用不同的统计器, 因为统计结果必须在要求的精度时间内进行输出. 例如当精度要求是小时, 用户连续在线1个小时, 并且横跨在2个自然小时上,......]]></content>
	<feedburner:origLink>http://blogread.cn/it/article.php?id=5400</feedburner:origLink></item>
	<item>
		<title>DNS Prefetching 技术引入及实现方法</title>
		<link>http://feedproxy.google.com/~r/blogreadIT/~3/ExSVBvP2grk/article.php</link>
		<author>蓝冰</author>
		<pubDate>2012-05-28 12:38:14</pubDate>
		<category domain="http://blogread.cn/it/category.php?id=7">JavaScript</category>
		<guid isPermaLink="false">http://blogread.cn/it/article.php?id=5399</guid>
		<comments>http://blogread.cn/it/article.php?id=5399#comment</comments>
		<description>&lt;p&gt;&lt;strong&gt;标签：&lt;/strong&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://blogread.cn/it/tags.php?tag=DNS" target="_blank"&gt;DNS&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://blogread.cn/it/tags.php?tag=Prefetching" target="_blank"&gt;Prefetching&lt;/a&gt;&lt;/p&gt;&lt;P&gt;DNS prefetching 是一个不算新的技术，谷歌和火狐都已经支持了。&lt;/P&gt;
&lt;P&gt;DNS prefetching 就是是 “DNS预获取”，假如你的网站是 a.com，但是你的网站内页含有大量的 b.com的引用，例如图片调用，那么，你可以使用下面的方法预先获知 b.com 的DNS，减少 打开下个页面的 获取DNS所需要的时间。其实都是毫秒级的，压力不大。本着技术讨论的角度简单说下。&lt;/P&gt;
&lt;P&gt;我直接来实例：&lt;/P&gt;
&lt;P&gt;本人博客henmang.net，含有大量来自0.gravatar.com和和1.gravatar.com的头像数据。&lt;/P&gt;
&lt;P&gt;于是，我加入了以下代码&lt;/P&gt;
&lt;DIV&gt;&lt;PRE&gt;&lt;FONT face="Courier New"&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #800000"&gt;link&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;rel&lt;/SPAN&gt;=&lt;SPAN style="COLOR: #0000ff"&gt;"dns-prefetch"&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;href&lt;/SPAN&gt;=&lt;SPAN style="COLOR: #0000ff"&gt;"http://0.gravatar.com"&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;/&amp;gt;&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #800000"&gt;link&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;rel&lt;/SPAN&gt;=&lt;SPAN style="COLOR: #0000ff"&gt;"dns-prefetch"&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;href&lt;/SPAN&gt;=&lt;SPAN style="COLOR: #0000ff"&gt;"http://1.gravatar.com"&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;/&amp;gt;&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/PRE&gt;&lt;/DIV&gt;
&lt;P&gt;当浏览器打开 henmang.net ，然后获取0.gravatar.com和1.gravatar.com的DNS，那么打开&lt;A title=http://henmang.net/html5prefetch.cgi href="http://henmang.net/html5prefetch.cgi"&gt;&lt;FONT color=#800080&gt;http://henmang.net/html5prefetch.cgi&lt;/FONT&gt;&lt;/A&gt; 的时候，就已经缓存了&lt;/P&gt;
&lt;P&gt;henmang.net&amp;nbsp; 0.gravatar.com&amp;nbsp; 1.gravatar.com&amp;nbsp; 三个域名的DNS，从而加快网站访问速度。&lt;/P&gt;
&lt;P&gt;========&lt;/P&gt;
&lt;P&gt;虽然文档是这么说的，不过我在Chrome下测试木检测到呢。&lt;/P&gt;
				&lt;p&gt;&lt;strong&gt;您可能还对下面的文章感兴趣：&lt;/strong&gt;&lt;/p&gt;
				&lt;p&gt;&lt;ol&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=4803" target="_blank"&gt;DNS&lt;/a&gt; [2012-01-24 13:32:17]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=4363" target="_blank"&gt;CentOS下通过Webmin管理BIND实现DNS轮询&lt;/a&gt; [2011-09-19 23:33:50]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=4195" target="_blank"&gt;DNS 隧道&lt;/a&gt; [2011-08-19 23:18:41]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=3169" target="_blank"&gt;强制刷新本地 DNS 缓存记录&lt;/a&gt; [2011-02-07 00:11:18]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=2970" target="_blank"&gt;大型网站用户定位技术&lt;/a&gt; [2011-01-05 22:45:41]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=2312" target="_blank"&gt;public DNS servers&lt;/a&gt; [2010-08-24 09:32:40]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=1243" target="_blank"&gt;Centos 下安装配置 PowerDNS&lt;/a&gt; [2010-03-24 23:32:49]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=995" target="_blank"&gt;关于 SOCKS 代理的远端 DNS 解析&lt;/a&gt; [2010-01-23 16:08:05]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=632" target="_blank"&gt;ubuntu 笔记之:如何修改dns&lt;/a&gt; [2009-11-18 13:43:50]&lt;/li&gt;&lt;/ol&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/m473fSsxMKCHkCvkvC0r5-406R4/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/m473fSsxMKCHkCvkvC0r5-406R4/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/m473fSsxMKCHkCvkvC0r5-406R4/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/m473fSsxMKCHkCvkvC0r5-406R4/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/blogreadIT/~4/ExSVBvP2grk" height="1" width="1"/&gt;</description>
		<content><![CDATA[DNS prefetching 是一个不算新的技术，谷歌和火狐都已经支持了。 DNS prefetching 就是是 “DNS预获取”，假如你的网站是 a.com，但是你的网站内页含有大量的....]]></content>
	<feedburner:origLink>http://blogread.cn/it/article.php?id=5399</feedburner:origLink></item>
	<item>
		<title>Typecho HTML5预加载</title>
		<link>http://feedproxy.google.com/~r/blogreadIT/~3/A41mK0SBIq8/article.php</link>
		<author>蓝冰</author>
		<pubDate>2012-05-28 12:37:36</pubDate>
		<category domain="http://blogread.cn/it/category.php?id=7">JavaScript</category>
		<guid isPermaLink="false">http://blogread.cn/it/article.php?id=5398</guid>
		<comments>http://blogread.cn/it/article.php?id=5398#comment</comments>
		<description>&lt;p&gt;&lt;strong&gt;标签：&lt;/strong&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://blogread.cn/it/tags.php?tag=Typecho" target="_blank"&gt;Typecho&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://blogread.cn/it/tags.php?tag=%E9%A2%84%E5%8A%A0%E8%BD%BD" target="_blank"&gt;预加载&lt;/a&gt;&lt;/p&gt;&lt;P&gt;天下文章一大抄，你通过搜索引擎搜索 HTML5预加载，估计只能找到诸如“ WP实现HTML5预加载”的方法。&lt;BR&gt;不知道的还以为只有WP可以实现HTML5预加载呢~&lt;BR&gt;火狐下引入的预加载使用方法&lt;BR&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #800000"&gt;link&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;rel&lt;/SPAN&gt;=&lt;SPAN style="COLOR: #0000ff"&gt;"prefetch"&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;href&lt;/SPAN&gt;=&lt;SPAN style="COLOR: #0000ff"&gt;"http://www.example.com/"&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;&lt;BR&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;文档 &lt;A href="http://en.wikipedia.org/wiki/Link_prefetching"&gt;&lt;FONT color=#0066cc&gt;http://en.wikipedia.org/wiki/Link_prefetching&lt;/FONT&gt;&lt;/A&gt;&lt;BR&gt;谷歌下预加载使用方法&lt;BR&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #800000"&gt;link&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;rel&lt;/SPAN&gt;=&lt;SPAN style="COLOR: #0000ff"&gt;"prerender"&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;href&lt;/SPAN&gt;=&lt;SPAN style="COLOR: #0000ff"&gt;"http://example.org/index.html"&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&lt;BR&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;文档&lt;A href="https://developers.google.com/chrome/whitepapers/prerender"&gt;&lt;FONT color=#0066cc&gt;https://developers.google.com/chrome/whitepapers/prerender&lt;/FONT&gt;&lt;/A&gt;&lt;/P&gt;&lt;!--more--&gt;
&lt;P&gt;代码如下：&lt;/P&gt;
&lt;DIV&gt;&lt;PRE&gt;&lt;STRIKE&gt;&lt;FONT face="Courier New"&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;&lt;/SPAN&gt;!-[if IE]&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #800000"&gt;script&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;src&lt;/SPAN&gt;=&lt;SPAN style="COLOR: #0000ff"&gt;"http://html5shiv.googlecode.com/svn/trunk/html5.js"&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: #800000"&gt;script&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;&lt;/SPAN&gt;![endif]-&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;?&lt;/SPAN&gt;php &lt;/FONT&gt;&lt;/STRIKE&gt;&lt;A style="COLOR: #0000ff" href="http://www.php.net/if"&gt;&lt;STRIKE&gt;&lt;FONT face="Courier New"&gt;if&lt;/FONT&gt;&lt;/STRIKE&gt;&lt;/A&gt;&lt;STRIKE&gt; ($this-&amp;gt;is('&lt;FONT face="Courier New"&gt;&lt;SPAN style="COLOR: #8b0000"&gt;index&lt;/SPAN&gt;')): &lt;SPAN style="COLOR: #0000ff"&gt;?&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt;&amp;lt;!-- 页面为首页时 --&amp;gt;&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #800000"&gt;link&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;rel&lt;/SPAN&gt;=&lt;SPAN style="COLOR: #0000ff"&gt;"prefetch"&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;href&lt;/SPAN&gt;=&lt;SPAN style="COLOR: #0000ff"&gt;"&amp;lt;?php $this-&amp;gt;options-&amp;gt;siteUrl(); ?&amp;gt;"&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;&lt;/SPAN&gt; &lt;SPAN style="COLOR: #008000"&gt;&amp;lt;!-- firefox --&amp;gt;&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #800000"&gt;link&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;rel&lt;/SPAN&gt;=&lt;SPAN style="COLOR: #0000ff"&gt;"prerender"&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;href&lt;/SPAN&gt;=&lt;SPAN style="COLOR: #0000ff"&gt;"&amp;lt;?php $this-&amp;gt;options-&amp;gt;siteUrl(); ?&amp;gt;"&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;&lt;/SPAN&gt; &lt;SPAN style="COLOR: #008000"&gt;&amp;lt;!-- chrome --&amp;gt;&lt;/SPAN&gt;
	&lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;?&lt;/SPAN&gt;php &lt;/FONT&gt;&lt;/STRIKE&gt;&lt;A style="COLOR: #0000ff" href="http://www.php.net/elseif"&gt;&lt;STRIKE&gt;&lt;FONT face="Courier New"&gt;elseif&lt;/FONT&gt;&lt;/STRIKE&gt;&lt;/A&gt;&lt;STRIKE&gt; ($this-&amp;gt;is('&lt;FONT face="Courier New"&gt;&lt;SPAN style="COLOR: #8b0000"&gt;post&lt;/SPAN&gt;')): &lt;SPAN style="COLOR: #0000ff"&gt;?&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt;&amp;lt;!-- 页面为文章单页时 --&amp;gt;&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #800000"&gt;link&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;rel&lt;/SPAN&gt;=&lt;SPAN style="COLOR: #0000ff"&gt;"prefetch"&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;href&lt;/SPAN&gt;=&lt;SPAN style="COLOR: #0000ff"&gt;"&amp;lt;?php $this-&amp;gt;permalink() ?&amp;gt;"&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;&lt;/SPAN&gt; &lt;SPAN style="COLOR: #008000"&gt;&amp;lt;!-- firefox --&amp;gt;&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #800000"&gt;link&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;rel&lt;/SPAN&gt;=&lt;SPAN style="COLOR: #0000ff"&gt;"prerender"&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;href&lt;/SPAN&gt;=&lt;SPAN style="COLOR: #0000ff"&gt;"&amp;lt;?php $this-&amp;gt;permalink() ?&amp;gt;"&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;&lt;/SPAN&gt; &lt;SPAN style="COLOR: #008000"&gt;&amp;lt;!-- chrome --&amp;gt;&lt;/SPAN&gt;
	&lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;?&lt;/SPAN&gt;php &lt;/FONT&gt;&lt;/STRIKE&gt;&lt;A style="COLOR: #0000ff" href="http://www.php.net/else"&gt;&lt;STRIKE&gt;&lt;FONT face="Courier New"&gt;else&lt;/FONT&gt;&lt;/STRIKE&gt;&lt;/A&gt;&lt;STRIKE&gt;: &lt;FONT face="Courier New"&gt;&lt;SPAN style="COLOR: #0000ff"&gt;?&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt;&amp;lt;!-- 页面为其他页时 --&amp;gt;&lt;/SPAN&gt;
	&lt;SPAN style="COLOR: #008000"&gt;&amp;lt;!-- 啥都木有 --&amp;gt;&lt;/SPAN&gt;
	&lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;?&lt;/SPAN&gt;php &lt;/FONT&gt;&lt;/STRIKE&gt;&lt;A style="COLOR: #0000ff" href="http://www.php.net/endif"&gt;&lt;STRIKE&gt;&lt;FONT face="Courier New"&gt;endif&lt;/FONT&gt;&lt;/STRIKE&gt;&lt;/A&gt;&lt;STRIKE&gt;; &lt;SPAN style="COLOR: #0000ff"&gt;&lt;FONT face="Courier New"&gt;?&amp;gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/STRIKE&gt;&lt;/PRE&gt;&lt;/DIV&gt;
&lt;P&gt;&lt;FONT face="Courier New"&gt;&lt;/FONT&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;上面的代码有错误。&lt;/P&gt;
&lt;P&gt;我仔细查找了国外的一些文档。&lt;/P&gt;
&lt;P&gt;例如 客户正在阅读 &lt;A href="http://henmang.net/DNSprefetching.cgi"&gt;&lt;FONT color=#0066cc&gt;http://henmang.net/DNSprefetching.cgi&lt;/FONT&gt;&lt;/A&gt; ，我们这里认为这是第一篇文章&lt;BR&gt;那么 客户很可能会去阅读 &lt;A href="http://henmang.net/html5prefetch.cgi"&gt;&lt;FONT color=#800080&gt;http://henmang.net/html5prefetch.cgi&lt;/FONT&gt;&lt;/A&gt; 我们认为这是第二篇文章。&lt;/P&gt;
&lt;P&gt;也就是我们post中的上一页下一页。&lt;/P&gt;
&lt;P&gt;因此，我们假设当前页面为B，上一页为A，下一页为C&lt;/P&gt;
&lt;P&gt;我们需要插入代码&lt;BR&gt;&amp;lt;link rel="prefetch" href="A"&amp;gt; &amp;lt;!-- firefox --&amp;gt;&lt;BR&gt;&amp;lt;link rel="prerender" href="A"&amp;gt; &amp;lt;!-- chrome --&amp;gt;&lt;BR&gt;&amp;lt;link rel="prefetch" href="C"&amp;gt; &amp;lt;!-- firefox --&amp;gt;&lt;BR&gt;&amp;lt;link rel="prerender" href="C"&amp;gt; &amp;lt;!-- chrome --&amp;gt;&lt;/P&gt;
&lt;P&gt;那么，在客户访问B页面的时候，浏览器会偷偷的加载 A和C的页面，如果索性客户点击了A和B页面，就是秒开了。。。&lt;/P&gt;
&lt;P&gt;但是我并不知道这个功能会不会降低 B页面的速度，如果会降低，显然是没有任何意义的，反而起了反作用。&lt;/P&gt;
&lt;P&gt;如果一定要做&lt;/P&gt;
&lt;P&gt;首页，预加载 最新一片日志&lt;/P&gt;
&lt;P&gt;文章页 ，预加载 上一页和下一页。&lt;/P&gt;
&lt;P&gt;因为考虑到效率等问题，做了下舍取，我只在post做预加载。&lt;/P&gt;
&lt;P&gt;代码如下，分为2部分&lt;/P&gt;
&lt;P&gt;第一部分，将以下代码加入functions.php ，代码来自 &lt;A title=http://jakc.net/post/444 href="http://jakc.net/post/444"&gt;&lt;FONT color=#0066cc&gt;http://jakc.net/post/444&lt;/FONT&gt;&lt;/A&gt; 有修改&lt;/P&gt;
&lt;DIV&gt;&lt;PRE&gt;&lt;FONT face="Courier New"&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;?&lt;/SPAN&gt;php
&lt;/FONT&gt;&lt;A style="COLOR: #0000ff" href="http://www.php.net/function"&gt;&lt;FONT face="Courier New"&gt;function&lt;/FONT&gt;&lt;/A&gt; xmPrevNext($method,$t,$isLink) 
        { 
        $xdb = Typecho_Db::get();       
        &lt;A style="COLOR: #0000ff" href="http://www.php.net/switch"&gt;&lt;FONT face="Courier New"&gt;switch&lt;/FONT&gt;&lt;/A&gt;($method){ 
            &lt;A style="COLOR: #0000ff" href="http://www.php.net/case"&gt;&lt;FONT face="Courier New"&gt;case&lt;/FONT&gt;&lt;/A&gt; "&lt;FONT face="Courier New"&gt;&lt;SPAN style="COLOR: #8b0000"&gt;pre&lt;/SPAN&gt;": 
                $xrs = $xdb-&amp;gt;fetchRow($xdb-&amp;gt;&lt;/FONT&gt;&lt;A style="COLOR: #ffa500" href="http://www.php.net/select"&gt;&lt;FONT face="Courier New"&gt;select&lt;/FONT&gt;&lt;/A&gt;()-&amp;gt;from('&lt;FONT face="Courier New"&gt;&lt;SPAN style="COLOR: #8b0000"&gt;table.contents&lt;/SPAN&gt;')    
                    -&amp;gt;where('&lt;SPAN style="COLOR: #8b0000"&gt;table.contents.created &amp;lt; ?&lt;/SPAN&gt;', $t-&amp;gt;created) 
                    -&amp;gt;where('&lt;SPAN style="COLOR: #8b0000"&gt;table.contents.status = ?&lt;/SPAN&gt;', '&lt;SPAN style="COLOR: #8b0000"&gt;publish&lt;/SPAN&gt;') 
                    -&amp;gt;where('&lt;SPAN style="COLOR: #8b0000"&gt;table.contents.type = ?&lt;/SPAN&gt;', $t-&amp;gt;type) 
                    -&amp;gt;where('&lt;SPAN style="COLOR: #8b0000"&gt;table.contents.password IS NULL&lt;/SPAN&gt;') 
                    -&amp;gt;order('&lt;SPAN style="COLOR: #8b0000"&gt;table.contents.created&lt;/SPAN&gt;', Typecho_Db::SORT_DESC) 
                    -&amp;gt;limit(1)); 
                 &lt;/FONT&gt;&lt;A style="COLOR: #0000ff" href="http://www.php.net/if"&gt;&lt;FONT face="Courier New"&gt;if&lt;/FONT&gt;&lt;/A&gt;(&lt;A style="COLOR: #ffa500" href="http://www.php.net/sizeof"&gt;&lt;FONT face="Courier New"&gt;sizeof&lt;/FONT&gt;&lt;/A&gt;($xrs)==0){ 
                    &lt;A style="COLOR: #0000ff" href="http://www.php.net/switch"&gt;&lt;FONT face="Courier New"&gt;switch&lt;/FONT&gt;&lt;/A&gt;($isLink){ 
                        &lt;A style="COLOR: #0000ff" href="http://www.php.net/case"&gt;&lt;FONT face="Courier New"&gt;case&lt;/FONT&gt;&lt;/A&gt; 0: 
                            &lt;A style="COLOR: #0000ff" href="http://www.php.net/echo"&gt;&lt;FONT face="Courier New"&gt;echo&lt;/FONT&gt;&lt;/A&gt; "&lt;FONT face="Courier New"&gt;&lt;SPAN style="COLOR: #8b0000"&gt;这已经是第一篇了亲~&lt;/SPAN&gt;"; 
                            &lt;/FONT&gt;&lt;A style="COLOR: #0000ff" href="http://www.php.net/break"&gt;&lt;FONT face="Courier New"&gt;break&lt;/FONT&gt;&lt;/A&gt;; 
                        &lt;A style="COLOR: #0000ff" href="http://www.php.net/case"&gt;&lt;FONT face="Courier New"&gt;case&lt;/FONT&gt;&lt;/A&gt; 1: 
                            &lt;A style="COLOR: #0000ff" href="http://www.php.net/echo"&gt;&lt;FONT face="Courier New"&gt;echo&lt;/FONT&gt;&lt;/A&gt; "&lt;FONT face="Courier New"&gt;&lt;SPAN style="COLOR: #8b0000"&gt;http://henmang.net&lt;/SPAN&gt;";  &lt;SPAN style="COLOR: #008000"&gt;//注意把这里修改为你本人的网址&lt;/SPAN&gt;
                            &lt;/FONT&gt;&lt;A style="COLOR: #0000ff" href="http://www.php.net/break"&gt;&lt;FONT face="Courier New"&gt;break&lt;/FONT&gt;&lt;/A&gt;; 
                    } 
                 } 
                &lt;A style="COLOR: #0000ff" href="http://www.php.net/break"&gt;&lt;FONT face="Courier New"&gt;break&lt;/FONT&gt;&lt;/A&gt;; 
            &lt;A style="COLOR: #0000ff" href="http://www.php.net/case"&gt;&lt;FONT face="Courier New"&gt;case&lt;/FONT&gt;&lt;/A&gt; '&lt;FONT face="Courier New"&gt;&lt;SPAN style="COLOR: #8b0000"&gt;next&lt;/SPAN&gt;': 
                $xrs = $xdb-&amp;gt;fetchRow($xdb-&amp;gt;&lt;/FONT&gt;&lt;A style="COLOR: #ffa500" href="http://www.php.net/select"&gt;&lt;FONT face="Courier New"&gt;select&lt;/FONT&gt;&lt;/A&gt;()-&amp;gt;from('&lt;FONT face="Courier New"&gt;&lt;SPAN style="COLOR: #8b0000"&gt;table.contents&lt;/SPAN&gt;')    
                    -&amp;gt;where('&lt;SPAN style="COLOR: #8b0000"&gt;table.contents.created &amp;gt; ?&lt;/SPAN&gt;',$t-&amp;gt;created) 
                    -&amp;gt;where('&lt;SPAN style="COLOR: #8b0000"&gt;table.contents.status = ?&lt;/SPAN&gt;', '&lt;SPAN style="COLOR: #8b0000"&gt;publish&lt;/SPAN&gt;') 
                    -&amp;gt;where('&lt;SPAN style="COLOR: #8b0000"&gt;table.contents.type = ?&lt;/SPAN&gt;', $t-&amp;gt;type) 
                    -&amp;gt;where('&lt;SPAN style="COLOR: #8b0000"&gt;table.contents.password IS NULL&lt;/SPAN&gt;') 
                    -&amp;gt;order('&lt;SPAN style="COLOR: #8b0000"&gt;table.contents.created&lt;/SPAN&gt;', Typecho_Db::SORT_ASC) 
                    -&amp;gt;limit(1)); 
                    &lt;/FONT&gt;&lt;A style="COLOR: #0000ff" href="http://www.php.net/if"&gt;&lt;FONT face="Courier New"&gt;if&lt;/FONT&gt;&lt;/A&gt;(&lt;A style="COLOR: #ffa500" href="http://www.php.net/sizeof"&gt;&lt;FONT face="Courier New"&gt;sizeof&lt;/FONT&gt;&lt;/A&gt;($xrs)==0){ 
                    &lt;A style="COLOR: #0000ff" href="http://www.php.net/switch"&gt;&lt;FONT face="Courier New"&gt;switch&lt;/FONT&gt;&lt;/A&gt;($isLink){ 
                        &lt;A style="COLOR: #0000ff" href="http://www.php.net/case"&gt;&lt;FONT face="Courier New"&gt;case&lt;/FONT&gt;&lt;/A&gt; 0: 
                            &lt;A style="COLOR: #0000ff" href="http://www.php.net/echo"&gt;&lt;FONT face="Courier New"&gt;echo&lt;/FONT&gt;&lt;/A&gt; "&lt;FONT face="Courier New"&gt;&lt;SPAN style="COLOR: #8b0000"&gt;木有下一篇了~&lt;/SPAN&gt;"; 
                            &lt;/FONT&gt;&lt;A style="COLOR: #0000ff" href="http://www.php.net/break"&gt;&lt;FONT face="Courier New"&gt;break&lt;/FONT&gt;&lt;/A&gt;; 
                        &lt;A style="COLOR: #0000ff" href="http://www.php.net/case"&gt;&lt;FONT face="Courier New"&gt;case&lt;/FONT&gt;&lt;/A&gt; 1: 
                            &lt;A style="COLOR: #0000ff" href="http://www.php.net/echo"&gt;&lt;FONT face="Courier New"&gt;echo&lt;/FONT&gt;&lt;/A&gt; "&lt;FONT face="Courier New"&gt;&lt;SPAN style="COLOR: #8b0000"&gt;http://henmang.net&lt;/SPAN&gt;";  &lt;SPAN style="COLOR: #008000"&gt;//注意把这里修改为你本人的网址&lt;/SPAN&gt;
                            &lt;/FONT&gt;&lt;A style="COLOR: #0000ff" href="http://www.php.net/break"&gt;&lt;FONT face="Courier New"&gt;break&lt;/FONT&gt;&lt;/A&gt;; 
                    } 
                 } 
                &lt;A style="COLOR: #0000ff" href="http://www.php.net/break"&gt;&lt;FONT face="Courier New"&gt;break&lt;/FONT&gt;&lt;/A&gt;; 
        } 
            &lt;A style="COLOR: #0000ff" href="http://www.php.net/if"&gt;&lt;FONT face="Courier New"&gt;if&lt;/FONT&gt;&lt;/A&gt;($xrs){ 
            $xrs = $t-&amp;gt;filter($xrs); 
            &lt;A style="COLOR: #0000ff" href="http://www.php.net/if"&gt;&lt;FONT face="Courier New"&gt;if&lt;/FONT&gt;&lt;/A&gt;($isLink==0){ 
                &lt;A style="COLOR: #0000ff" href="http://www.php.net/echo"&gt;&lt;FONT face="Courier New"&gt;echo&lt;/FONT&gt;&lt;/A&gt; $xrs['&lt;FONT face="Courier New"&gt;&lt;SPAN style="COLOR: #8b0000"&gt;title&lt;/SPAN&gt;']; 
            }&lt;/FONT&gt;&lt;A style="COLOR: #0000ff" href="http://www.php.net/else"&gt;&lt;FONT face="Courier New"&gt;else&lt;/FONT&gt;&lt;/A&gt;{ 
                &lt;A style="COLOR: #0000ff" href="http://www.php.net/echo"&gt;&lt;FONT face="Courier New"&gt;echo&lt;/FONT&gt;&lt;/A&gt; $xrs['&lt;SPAN style="COLOR: #8b0000"&gt;&lt;FONT face="Courier New"&gt;permalink&lt;/FONT&gt;&lt;/SPAN&gt;']; 
                } 
            } 
        } &lt;/PRE&gt;&lt;/DIV&gt;
&lt;P&gt;然后在header.php加入&lt;/P&gt;
&lt;DIV&gt;&lt;PRE&gt;&lt;FONT face="Courier New"&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;?&lt;/SPAN&gt;php &lt;/FONT&gt;&lt;A style="COLOR: #0000ff" href="http://www.php.net/if"&gt;&lt;FONT face="Courier New"&gt;if&lt;/FONT&gt;&lt;/A&gt; ($this-&amp;gt;is('&lt;FONT face="Courier New"&gt;&lt;SPAN style="COLOR: #8b0000"&gt;post&lt;/SPAN&gt;')): &lt;SPAN style="COLOR: #0000ff"&gt;?&amp;gt;&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;&lt;/SPAN&gt;!--[if IE]&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #800000"&gt;script&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;src&lt;/SPAN&gt;=&lt;SPAN style="COLOR: #0000ff"&gt;"http://html5shiv.googlecode.com/svn/trunk/html5.js"&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: #800000"&gt;script&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;&lt;/SPAN&gt;![endif]-&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #800000"&gt;link&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;rel&lt;/SPAN&gt;=&lt;SPAN style="COLOR: #0000ff"&gt;"prefetch"&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;href&lt;/SPAN&gt;=&lt;SPAN style="COLOR: #0000ff"&gt;"&amp;lt;?php xmPrevNext("&lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;pre&lt;/SPAN&gt;",$&lt;SPAN style="COLOR: #ff0000"&gt;this&lt;/SPAN&gt;,&lt;SPAN style="COLOR: #ff0000"&gt;1&lt;/SPAN&gt;); ?&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;&lt;/SPAN&gt;"&amp;gt; &lt;SPAN style="COLOR: #008000"&gt;&amp;lt;!-- firefox --&amp;gt;&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #800000"&gt;link&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;rel&lt;/SPAN&gt;=&lt;SPAN style="COLOR: #0000ff"&gt;"prefetch"&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;href&lt;/SPAN&gt;=&lt;SPAN style="COLOR: #0000ff"&gt;"&amp;lt;?php xmPrevNext("&lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;next&lt;/SPAN&gt;",$&lt;SPAN style="COLOR: #ff0000"&gt;this&lt;/SPAN&gt;,&lt;SPAN style="COLOR: #ff0000"&gt;1&lt;/SPAN&gt;); ?&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;&lt;/SPAN&gt;"&amp;gt; &lt;SPAN style="COLOR: #008000"&gt;&amp;lt;!-- firefox --&amp;gt;&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #800000"&gt;link&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;rel&lt;/SPAN&gt;=&lt;SPAN style="COLOR: #0000ff"&gt;"prerender"&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;href&lt;/SPAN&gt;=&lt;SPAN style="COLOR: #0000ff"&gt;"&amp;lt;?php xmPrevNext("&lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;pre&lt;/SPAN&gt;",$&lt;SPAN style="COLOR: #ff0000"&gt;this&lt;/SPAN&gt;,&lt;SPAN style="COLOR: #ff0000"&gt;1&lt;/SPAN&gt;); ?&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;&lt;/SPAN&gt;"&amp;gt; &lt;SPAN style="COLOR: #008000"&gt;&amp;lt;!-- chrome --&amp;gt;&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #800000"&gt;link&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;rel&lt;/SPAN&gt;=&lt;SPAN style="COLOR: #0000ff"&gt;"prerender"&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;href&lt;/SPAN&gt;=&lt;SPAN style="COLOR: #0000ff"&gt;"&amp;lt;?php xmPrevNext("&lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;next&lt;/SPAN&gt;",$&lt;SPAN style="COLOR: #ff0000"&gt;this&lt;/SPAN&gt;,&lt;SPAN style="COLOR: #ff0000"&gt;1&lt;/SPAN&gt;); ?&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;&lt;/SPAN&gt;"&amp;gt; &lt;SPAN style="COLOR: #008000"&gt;&amp;lt;!-- chrome --&amp;gt;&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;?&lt;/SPAN&gt;php &lt;/FONT&gt;&lt;A style="COLOR: #0000ff" href="http://www.php.net/endif"&gt;&lt;FONT face="Courier New"&gt;endif&lt;/FONT&gt;&lt;/A&gt;; &lt;SPAN style="COLOR: #0000ff"&gt;&lt;FONT face="Courier New"&gt;?&amp;gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/PRE&gt;&lt;/DIV&gt;
&lt;P&gt;如果你一定要在首页预加载第一篇日志，可以试试下面的代码，很蛋疼&lt;/P&gt;
&lt;DIV&gt;&lt;PRE&gt;&lt;FONT face="Courier New"&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;&lt;/SPAN&gt;!--[if IE]&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #800000"&gt;script&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;src&lt;/SPAN&gt;=&lt;SPAN style="COLOR: #0000ff"&gt;"http://html5shiv.googlecode.com/svn/trunk/html5.js"&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: #800000"&gt;script&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;&lt;/SPAN&gt;![endif]-&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;?&lt;/SPAN&gt;php &lt;/FONT&gt;&lt;A style="COLOR: #0000ff" href="http://www.php.net/if"&gt;&lt;FONT face="Courier New"&gt;if&lt;/FONT&gt;&lt;/A&gt; ($this-&amp;gt;is('&lt;FONT face="Courier New"&gt;&lt;SPAN style="COLOR: #8b0000"&gt;index&lt;/SPAN&gt;')): &lt;SPAN style="COLOR: #0000ff"&gt;?&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt;&amp;lt;!-- 页面为首页时 --&amp;gt;&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #800000"&gt;link&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;rel&lt;/SPAN&gt;=&lt;SPAN style="COLOR: #0000ff"&gt;"prefetch"&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;href&lt;/SPAN&gt;=&lt;SPAN style="COLOR: #0000ff"&gt;"&amp;lt;?php $this-&amp;gt;widget('Widget_Contents_Post_Recent', 'pageSize=1')-&amp;gt;parse('{permalink}'); ?&amp;gt;"&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;&lt;/SPAN&gt; &lt;SPAN style="COLOR: #008000"&gt;&amp;lt;!-- firefox --&amp;gt;&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #800000"&gt;link&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;rel&lt;/SPAN&gt;=&lt;SPAN style="COLOR: #0000ff"&gt;"prerender"&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;href&lt;/SPAN&gt;=&lt;SPAN style="COLOR: #0000ff"&gt;"&amp;lt;?php $this-&amp;gt;widget('Widget_Contents_Post_Recent', 'pageSize=1')-&amp;gt;parse('{permalink}'); ?&amp;gt;"&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;&lt;/SPAN&gt; &lt;SPAN style="COLOR: #008000"&gt;&amp;lt;!-- chrome --&amp;gt;&lt;/SPAN&gt;
	&lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;?&lt;/SPAN&gt;php &lt;/FONT&gt;&lt;A style="COLOR: #0000ff" href="http://www.php.net/elseif"&gt;&lt;FONT face="Courier New"&gt;elseif&lt;/FONT&gt;&lt;/A&gt; ($this-&amp;gt;is('&lt;FONT face="Courier New"&gt;&lt;SPAN style="COLOR: #8b0000"&gt;post&lt;/SPAN&gt;')): &lt;SPAN style="COLOR: #0000ff"&gt;?&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt;&amp;lt;!-- 页面为文章单页时 --&amp;gt;&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #800000"&gt;link&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;rel&lt;/SPAN&gt;=&lt;SPAN style="COLOR: #0000ff"&gt;"prefetch"&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;href&lt;/SPAN&gt;=&lt;SPAN style="COLOR: #0000ff"&gt;"&amp;lt;?php xmPrevNext("&lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;pre&lt;/SPAN&gt;",$&lt;SPAN style="COLOR: #ff0000"&gt;this&lt;/SPAN&gt;,&lt;SPAN style="COLOR: #ff0000"&gt;1&lt;/SPAN&gt;); ?&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;&lt;/SPAN&gt;"&amp;gt; &lt;SPAN style="COLOR: #008000"&gt;&amp;lt;!-- firefox --&amp;gt;&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #800000"&gt;link&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;rel&lt;/SPAN&gt;=&lt;SPAN style="COLOR: #0000ff"&gt;"prefetch"&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;href&lt;/SPAN&gt;=&lt;SPAN style="COLOR: #0000ff"&gt;"&amp;lt;?php xmPrevNext("&lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;next&lt;/SPAN&gt;",$&lt;SPAN style="COLOR: #ff0000"&gt;this&lt;/SPAN&gt;,&lt;SPAN style="COLOR: #ff0000"&gt;1&lt;/SPAN&gt;); ?&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;&lt;/SPAN&gt;"&amp;gt; &lt;SPAN style="COLOR: #008000"&gt;&amp;lt;!-- firefox --&amp;gt;&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #800000"&gt;link&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;rel&lt;/SPAN&gt;=&lt;SPAN style="COLOR: #0000ff"&gt;"prerender"&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;href&lt;/SPAN&gt;=&lt;SPAN style="COLOR: #0000ff"&gt;"&amp;lt;?php xmPrevNext("&lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;pre&lt;/SPAN&gt;",$&lt;SPAN style="COLOR: #ff0000"&gt;this&lt;/SPAN&gt;,&lt;SPAN style="COLOR: #ff0000"&gt;1&lt;/SPAN&gt;); ?&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;&lt;/SPAN&gt;"&amp;gt; &lt;SPAN style="COLOR: #008000"&gt;&amp;lt;!-- chrome --&amp;gt;&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #800000"&gt;link&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;rel&lt;/SPAN&gt;=&lt;SPAN style="COLOR: #0000ff"&gt;"prerender"&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;href&lt;/SPAN&gt;=&lt;SPAN style="COLOR: #0000ff"&gt;"&amp;lt;?php xmPrevNext("&lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;next&lt;/SPAN&gt;",$&lt;SPAN style="COLOR: #ff0000"&gt;this&lt;/SPAN&gt;,&lt;SPAN style="COLOR: #ff0000"&gt;1&lt;/SPAN&gt;); ?&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;&lt;/SPAN&gt;"&amp;gt; &lt;SPAN style="COLOR: #008000"&gt;&amp;lt;!-- chrome --&amp;gt;&lt;/SPAN&gt;
	&lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;?&lt;/SPAN&gt;php &lt;/FONT&gt;&lt;A style="COLOR: #0000ff" href="http://www.php.net/else"&gt;&lt;FONT face="Courier New"&gt;else&lt;/FONT&gt;&lt;/A&gt;: &lt;FONT face="Courier New"&gt;&lt;SPAN style="COLOR: #0000ff"&gt;?&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt;&amp;lt;!-- 页面为其他页时 --&amp;gt;&lt;/SPAN&gt;
	&lt;SPAN style="COLOR: #008000"&gt;&amp;lt;!-- 啥都木有 --&amp;gt;&lt;/SPAN&gt;
	&lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;?&lt;/SPAN&gt;php &lt;/FONT&gt;&lt;A style="COLOR: #0000ff" href="http://www.php.net/endif"&gt;&lt;FONT face="Courier New"&gt;endif&lt;/FONT&gt;&lt;/A&gt;; &lt;SPAN style="COLOR: #0000ff"&gt;&lt;FONT face="Courier New"&gt;?&amp;gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/PRE&gt;&lt;/DIV&gt;
				&lt;p&gt;&lt;strong&gt;您可能还对下面的文章感兴趣：&lt;/strong&gt;&lt;/p&gt;
				&lt;p&gt;&lt;ol&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=443" target="_blank"&gt;js实现预加载图片让图片快速显示&lt;/a&gt; [2009-11-04 13:34:18]&lt;/li&gt;&lt;/ol&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/59zoR_m34as3rlaHDeyNiW3boas/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/59zoR_m34as3rlaHDeyNiW3boas/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/59zoR_m34as3rlaHDeyNiW3boas/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/59zoR_m34as3rlaHDeyNiW3boas/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/blogreadIT/~4/A41mK0SBIq8" height="1" width="1"/&gt;</description>
		<content><![CDATA[天下文章一大抄，你通过搜索引擎搜索 HTML5预加载，估计只能找到诸如“ WP实现HTML5预加载”的方法。 不知道的还以为只有WP可以实现HEML5预加载呢~ 火狐下引入的预加载使用方法]]></content>
	<feedburner:origLink>http://blogread.cn/it/article.php?id=5398</feedburner:origLink></item>
	<item>
		<title>使用Javascript获取页面所在目录的绝对路径</title>
		<link>http://feedproxy.google.com/~r/blogreadIT/~3/o-PVWULp7aQ/article.php</link>
		<author>Heero's Blog</author>
		<pubDate>2012-05-28 12:36:58</pubDate>
		<category domain="http://blogread.cn/it/category.php?id=7">JavaScript</category>
		<guid isPermaLink="false">http://blogread.cn/it/article.php?id=5397</guid>
		<comments>http://blogread.cn/it/article.php?id=5397#comment</comments>
		<description>&lt;p&gt;&lt;strong&gt;标签：&lt;/strong&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://blogread.cn/it/tags.php?tag=%E7%BB%9D%E5%AF%B9%E8%B7%AF%E5%BE%84" target="_blank"&gt;绝对路径&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://blogread.cn/it/tags.php?tag=%E8%B7%AF%E5%BE%84" target="_blank"&gt;路径&lt;/a&gt;&lt;/p&gt;&lt;DIV class=article-content&gt;
&lt;P&gt;&lt;SPAN style="DISPLAY: none" id=__kindeditor_bookmark_start_148__&gt;&lt;/SPAN&gt;一谈到路径相关的问题，大家都会往&lt;STRONG&gt;window.location&lt;/STRONG&gt;上想，确实这个对象提供了相当多的路径信息，其中常用的就包括： &lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;location.href：当前页面的完整URL &lt;/LI&gt;
&lt;LI&gt;location.pathname：当前URL中的路径名 &lt;/LI&gt;
&lt;LI&gt;location.hash：当前URL中的锚点 &lt;/LI&gt;
&lt;LI&gt;location.search：当前URL中的查询参数 &lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;然而，location没有一个属性能直接获得&lt;STRONG&gt;当前目录（不含文件名&lt;/STRONG&gt;&lt;STRONG&gt;）&lt;/STRONG&gt;的绝对路径。通过Google我发现了一些错误的方法，比如说把URL通过“/”分离成数组，把数组的最后一项去掉以后再连接成字符串。但如果URL中没有指定文件名，结果就大错特错了。 &lt;/P&gt;
&lt;P&gt;根据以往编码的经验，我记得&lt;STRONG&gt;a元素的href属性总是会返回绝对路径&lt;/STRONG&gt;，也就是说它具有把相对路径转成绝对路径的能力。使用下面的代码尝试了一下，果然成了： &lt;/P&gt;&lt;PRE class="prettyprint lang-js"&gt;var a = document.createElement('a');
a.href = './';
alert(a.href);
a = null;&lt;/PRE&gt;
&lt;P&gt;很不幸地，此方法在老旧的IE 6/7下无效，当执行alert(a.href)时，弹出的仍然是“./”。后来，我发现在Stackoverflow上也有人提出了这个问题，而解决方法也是很简单的，只要&lt;STRONG&gt;把a通过innerHTML注入&lt;/STRONG&gt;就可以了： &lt;/P&gt;&lt;PRE class="prettyprint lang-js"&gt;var div = document.createElement('div');
div.innerHTML = '&amp;lt;a href="./"&amp;gt;&amp;lt;/a&amp;gt;";
alert(div.firstChild.href);
div = null;&lt;/PRE&gt;
&lt;P&gt;有人可能会问：为何不用正则表达式？我的答案是：要考虑有无文件名的情况、有无锚点的情况、有无查询参数的情况，这条正则表达式可能会挺复杂的。 &lt;/P&gt;&lt;/DIV&gt;
				&lt;p&gt;&lt;strong&gt;您可能还对下面的文章感兴趣：&lt;/strong&gt;&lt;/p&gt;
				&lt;p&gt;&lt;ol&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=1355" target="_blank"&gt;XML路径语言:XPath&lt;/a&gt; [2010-04-13 10:57:41]&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogread.cn/it/article.php?id=1159" target="_blank"&gt;htaccess二级目录重写找不到路径&lt;/a&gt; [2010-03-08 23:11:31]&lt;/li&gt;&lt;/ol&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/lkvPODug7548b2nDi9bDvU-ZluA/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/lkvPODug7548b2nDi9bDvU-ZluA/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/lkvPODug7548b2nDi9bDvU-ZluA/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/lkvPODug7548b2nDi9bDvU-ZluA/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/blogreadIT/~4/o-PVWULp7aQ" height="1" width="1"/&gt;</description>
		<content><![CDATA[一谈到路径相关的问题，大家都会往window.location上想，确实这个对象提供了相当多的路径信息，其中常用的就包括： location.href：当前页面的完整URL location.pathname：当前URL中的路径名 location.hash：当前URL中的锚点 location.search：当前URL中的查询参数 然而，location没有一个属性能直接获得当前目录(不含文件名)的绝对路径。通过Google我发现了一些错误的方法，比如说把URL通过“/”分离成数组，把数组的最后一项去掉以后再连接成字符串。如果是这种URL模式，那自然没问题： http://域名/路径/文件名 但如果URL中没有指定文件名，结果就大错特错了： http://域名/路径 ]]></content>
	<feedburner:origLink>http://blogread.cn/it/article.php?id=5397</feedburner:origLink></item>
	<item>
		<title>sql_id和hash value的部分转换</title>
		<link>http://feedproxy.google.com/~r/blogreadIT/~3/ofhSYEm49Tk/article.php</link>
		<author>惜分飞</author>
		<pubDate>2012-05-28 12:36:17</pubDate>
		<category domain="http://blogread.cn/it/category.php?id=4">Oracle</category>
		<guid isPermaLink="false">http://blogread.cn/it/article.php?id=5396</guid>
		<comments>http://blogread.cn/it/article.php?id=5396#comment</comments>
		<description>&lt;p&gt;&lt;strong&gt;标签：&lt;/strong&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://blogread.cn/it/tags.php?tag=hash%20value" target="_blank"&gt;hash value&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://blogread.cn/it/tags.php?tag=sql_id" target="_blank"&gt;sql_id&lt;/a&gt;&lt;/p&gt;&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;从oracle 10g开始引进了sql_id，在老版本的oralce中,要表明一条sql,一般使用hash value，而在10g及其以后版本中一般建议使用sql_id,从9i的sp和10g的awr中也可以看出.对于Library Cache对象,Oracle使用MD5算法进行哈希,生成一个128位的Hash Value,其中低32位作为HASH VALUE显示,SQL_ID则取了后64位.既然hash value和sql_id之前存在着这样的关系,那么我们就可以通过函数实现两者的部分转换(因为最终取值长度不同,所以不能完全转换)&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;STRONG&gt;1.查询sql_id和hash value&lt;/STRONG&gt;&lt;/P&gt;&lt;PRE class="brush: sql; title: ; notranslate"&gt;SQL&amp;gt; select * from v$version;

BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - 64bi
PL/SQL Release 10.2.0.4.0 - Production
CORE    10.2.0.4.0      Production
TNS for Linux: Version 10.2.0.4.0 - Production
NLSRTL Version 10.2.0.4.0 - Production

SQL&amp;gt; select to_char(sysdate,\'yyyy-mm-dd hh24:mi:ss\')
  2  "www.xifenfei.com" from dual;

www.xifenfei.com
-------------------
2012-05-26 01:05:39

SQL&amp;gt; select sql_id,hash_value from v$sql where sql_text like
  2  \'select * from dual\';

SQL_ID        HASH_VALUE
------------- ----------
a5ks9fhw2v9s1  942515969
&lt;/PRE&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;STRONG&gt;2.oracle自带函数转换sql_id to hash value&lt;/STRONG&gt;&lt;/P&gt;&lt;PRE class="brush: sql; title: ; notranslate"&gt;SQL&amp;gt; select dbms_utility.SQLID_TO_SQLHASH(\'a5ks9fhw2v9s1\') hash_value FROM DUAL;

HASH_VALUE
----------
 942515969
&lt;/PRE&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;STRONG&gt;3.自己编写函数sql_id to hash value&lt;/STRONG&gt;&lt;/P&gt;&lt;PRE class="brush: sql; title: ; notranslate"&gt;SQL&amp;gt; CREATE OR REPLACE FUNCTION sql_id_2_hash_value (sql_id VARCHAR2)
  2     RETURN NUMBER
  3  IS
  4     l_output   NUMBER := 0;
  5  BEGIN
  6         SELECT TRUNC (
  7                   MOD (
  8                      SUM (
  9                         (INSTR (\'0123456789abcdfghjkmnpqrstuvwxyz\',
 10                                 SUBSTR (LOWER (TRIM (sql_id)), LEVEL, 1))
 11                          - 1)
 12                         * POWER (32, LENGTH (TRIM (sql_id)) - LEVEL)),
 13                      POWER (2, 32)))
 14           INTO l_output
 15           FROM DUAL
 16     CONNECT BY LEVEL &amp;lt;= LENGTH (TRIM (sql_id));
 17     RETURN l_output;
 18  END;
 19  /

函数已创建。

SQL&amp;gt; select sql_id_2_hash_value(\'a5ks9fhw2v9s1\') hash_value FROM DUAL;

HASH_VALUE
----------
 942515969
&lt;/PRE&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;STRONG&gt;4.hash value 转换为部分 sql_id&lt;/STRONG&gt;&lt;/P&gt;&lt;PRE class="brush: sql; title: ; notranslate"&gt;SQL&amp;gt; CREATE OR REPLACE FUNCTION hash_value_2_sql_id (p_hash_value NUMBER)
  2     RETURN VARCHAR2
  3  IS
  4     l_output   VARCHAR2 (8) := \'\';
  5  BEGIN
  6     FOR i
  7        IN (    SELECT SUBSTR (
  8                          \'0123456789abcdfghjkmnpqrstuvwxyz\',
  9                          1
 10                          + FLOOR (
 11                               MOD (p_hash_value / (POWER (32, LEVEL - 1)), 32)),
 12                          1)
 13                          sqlidchar
 14                  FROM DUAL
 15            CONNECT BY LEVEL &amp;lt;= LN (p_hash_value) / LN (32)
 16              ORDER BY LEVEL DESC)
 17     LOOP
 18        l_output := l_output || i.sqlidchar;
 19     END LOOP;
 20
 21     RETURN l_output;
 22  END;
 23  /

函数已创建。

SQL&amp;gt; select hash_value_2_sql_id(942515969) from dual;

HASH_VALUE_2_SQL_ID(942515969)
--------------------------------------------------------
2v9s1
&lt;/PRE&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;参考:&lt;A title="SQL_ID is just a fancy representation of hash value" href="http://blog.tanelpoder.com/2009/02/22/sql_id-is-just-a-fancy-representation-of-hash-value/" target=_blank&gt;http://blog.tanelpoder.com/2009/02/22/sql_id-is-just-a-fancy-representation-of-hash-value/&lt;/A&gt;&lt;/P&gt;
				&lt;p&gt;&lt;strong&gt;您可能还对下面的文章感兴趣：&lt;/strong&gt;&lt;/p&gt;
				&lt;p&gt;很抱歉，暂时没有...... &lt;/p&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/mdUtjUImLUle3VX-K9OURr5InSE/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/mdUtjUImLUle3VX-K9OURr5InSE/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/mdUtjUImLUle3VX-K9OURr5InSE/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/mdUtjUImLUle3VX-K9OURr5InSE/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/blogreadIT/~4/ofhSYEm49Tk" height="1" width="1"/&gt;</description>
		<content><![CDATA[从oracle 10g开始引进了sql_id，在老版本的oralce中,要表明一条sql,一般使用hash value，而在10g及其以后版本中一般建议使用sql_id,从9i的sp和10g的awr中也可以看出.对于Library Cache对象,Oracle使用MD5算法进行哈希,生成一个128位的Hash Value,其中低32位作为HASH VALUE显示,SQL_ID则取了后64位.既然hash value和sql_id之前存在着这样的关系,那么我们就可以通过函数实现两者的部分转换(因为最终取值长度不同,所以不能完全转换) 1.查询sql_id和hash value 2.oracle自带函数转换sql_id to hash value 3.自己编写函数sql_id to hash value 4.hash value 转换为部分 sql_id ]]></content>
	<feedburner:origLink>http://blogread.cn/it/article.php?id=5396</feedburner:origLink></item>
</channel>
</rss>

