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

<channel>
	<title>shell&#039;s home</title>
	<atom:link href="http://shell909090.com/blog/feed/" rel="self" type="application/rss+xml" />
	<link>http://shell909090.com/blog</link>
	<description>贝壳的壳</description>
	<lastBuildDate>Fri, 18 May 2012 07:37:41 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<item>
		<title>语言的效率差异2</title>
		<link>http://shell909090.com/blog/2012/05/%e8%af%ad%e8%a8%80%e7%9a%84%e6%95%88%e7%8e%87%e5%b7%ae%e5%bc%822/</link>
		<comments>http://shell909090.com/blog/2012/05/%e8%af%ad%e8%a8%80%e7%9a%84%e6%95%88%e7%8e%87%e5%b7%ae%e5%bc%822/#comments</comments>
		<pubDate>Thu, 17 May 2012 23:14:24 +0000</pubDate>
		<dc:creator>shell</dc:creator>
				<category><![CDATA[其他]]></category>

		<guid isPermaLink="false">http://shell909090.com/blog/?p=2174</guid>
		<description><![CDATA[# 问题 # 为了更深入的测试语言，我做了一个经典问题——24点。 这个问题主要是测试递归，循环效率，还有数组和树的复制性能。 为了简化问题，方便测试，我的问题是这样描述的： &#62; 有一个数组，里面有多个正整数。有一个操作数组，其中每个都是双目操作符。找出以两者构成算式，其值等于给定值的所有表达式组合。 &#62; 要求不得遗漏，可以有少量重复。例如可交换算符的交换同构暂不做排重。 实际运行的时候，取+-*/和3 4 6 8，运行100次，查看时间消耗。正确的单次输出结果应当是这样的。 &#62; (((8 + 4) / 3) * 6) = 24 &#62; (6 / (3 / (8 + 4))) = 24 &#62; (((8 + 4) * 6) &#8230; <a href="http://shell909090.com/blog/2012/05/%e8%af%ad%e8%a8%80%e7%9a%84%e6%95%88%e7%8e%87%e5%b7%ae%e5%bc%822/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<div># 问题 #</div>
<div>为了更深入的测试语言，我做了一个经典问题——24点。</div>
<div>这个问题主要是测试递归，循环效率，还有数组和树的复制性能。</div>
<div>为了简化问题，方便测试，我的问题是这样描述的：</div>
<div></div>
<div>&gt; 有一个数组，里面有多个正整数。有一个操作数组，其中每个都是双目操作符。找出以两者构成算式，其值等于给定值的所有表达式组合。</div>
<div>
<p>&gt; 要求不得遗漏，可以有少量重复。例如可交换算符的交换同构暂不做排重。</p></div>
<div></div>
<div>实际运行的时候，取+-*/和3 4 6 8，运行100次，查看时间消耗。正确的单次输出结果应当是这样的。</div>
<div></div>
<div>&gt; (((8 + 4) / 3) * 6) = 24</div>
<div>&gt; (6 / (3 / (8 + 4))) = 24</div>
<div>
<p>&gt; (((8 + 4) * 6) / 3) = 24</p></div>
<div>&gt; (((8 / 4) + 6) * 3) = 24</div>
<div>&gt; (((8 &#8211; 6) * 3) * 4) = 24</div>
<div>&gt; (((8 &#8211; 6) * 4) * 3) = 24</div>
<div>&gt; (((3 * 4) &#8211; <img src='http://shell909090.com/blog/wp-includes/images/smilies/icon_cool.gif' alt='8)' class='wp-smiley' /> * 6) = 24</div>
<div>&gt; ((8 &#8211; (6 / 3)) * 4) = 24</div>
<div>&gt; (((4 + <img src='http://shell909090.com/blog/wp-includes/images/smilies/icon_cool.gif' alt='8)' class='wp-smiley' /> / 3) * 6) = 24</div>
<div>&gt; (6 / (3 / (4 + 8))) = 24</div>
<div>&gt; (((4 + <img src='http://shell909090.com/blog/wp-includes/images/smilies/icon_cool.gif' alt='8)' class='wp-smiley' /> * 6) / 3) = 24</div>
<div>&gt; (((8 / 4) + 6) * 3) = 24</div>
<div>&gt; (((4 * 3) &#8211; <img src='http://shell909090.com/blog/wp-includes/images/smilies/icon_cool.gif' alt='8)' class='wp-smiley' /> * 6) = 24</div>
<div>&gt; (((8 &#8211; 6) * 3) * 4) = 24</div>
<div>&gt; (((8 &#8211; 6) * 4) * 3) = 24</div>
<div>&gt; ((8 &#8211; (6 / 3)) * 4) = 24</div>
<div></div>
<div># python #</div>
<div>python的解很复杂，长达31行，以下是我写的解。当然，还有更简单的版本，我可以用eval来干这个事情，代码只有24行，但是确实给人很evil的感觉。</div>
<div></div>
<div>
<p><span class="Apple-tab-span" style="white-space:pre">	</span>from itertools import combinations</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>class opt(object):</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>    def __init__(self, name, func, ex=True):</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>        <a href="http://self.name">self.name</a>, self.func, self.exchangable = name, func, ex</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>    def __str__(self): return <a href="http://self.name">self.name</a></div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>    def __call__(self, l, r): return self.func(l, r)</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>    def fmt(self, l, r):</div>
<div> <span class="Apple-tab-span" style="white-space:pre">	</span>        return &#39;(%s %s %s)&#39; % (fmt_exp(l), str(self), fmt_exp(r))</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>def eval_exp(e):</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>    if not isinstance(e, tuple): return e</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>    try: return e[0](eval_exp(e[1]), eval_exp(e[2]))</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>    except: return None</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>def fmt_exp(e): return e[0].fmt(e[1], e[2]) if isinstance(e, tuple) else str(e)</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>def print_exp(e): print fmt_exp(e), eval_exp(e)</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>def chkexp(target):</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>    def do_exp(e):</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>        if abs(eval_exp(e) &#8211; target) &lt; 0.001: print fmt_exp(e), &#39;=&#39;, target</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>    return do_exp</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>def iter_all_exp(f, ops, ns, e=None):</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>    if not ns: return f(e)</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>    for r in set(ns):</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>        ns.remove(r)</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>        if e is None: iter_all_exp(f, ops, ns, r)</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>        else:</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>            for op in ops:</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>                iter_all_exp(f, ops, ns, (op, e, r))</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>                if not op.exchangable:</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>                    iter_all_exp(f, ops, ns, (op, r, e))</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>        ns.append(r)</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>opts = [</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>    opt(&#39;+&#39;, lambda x, y: x+y),</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>    opt(&#39;-&#39;, lambda x, y: x-y, False),</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>    opt(&#39;*&#39;, lambda x, y: x*y),</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>    opt(&#39;/&#39;, lambda x, y: float(x)/y, False),]</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>if __name__ == &#39;__main__&#39;:</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>    for i in xrange(100): iter_all_exp(chkexp(24), opts, [3, 4, 6, 8])</div>
<div></div>
<div>以下是100次的时间：</div>
<div>&gt; real<span class="Apple-tab-span" style="white-space:pre">	</span>0m2.259s</div>
<div>&gt; user<span class="Apple-tab-span" style="white-space:pre">	</span>0m2.248s</div>
<div>&gt; sys<span class="Apple-tab-span" style="white-space:pre">	</span>0m0.004s</div>
<div></div>
<div># common lisp #</div>
<div>
<p>lisp来解这个问题简直是作弊，难怪被叫做人工智能语言。</p></div>
<div></div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>(defun chkexp (target)</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>  (lambda (e)</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>    (if (equal (ignore-errors (eval e)) target) (print e))))</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>(defun exchangeable (op)</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>  (not (member op &#39;(- /))))</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>(defun iter-all-exp (f ops ns &amp;optional e)</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>  (cond</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>    ((not ns) (funcall f e))</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>    ((not e) (dolist (r (remove-duplicates ns))</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>       (iter-all-exp f ops (remove r ns :count 1) r)))</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>    (t (dolist (r (remove-duplicates ns))</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span> (let ((nss (remove r ns :count 1)))</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>   (dolist (op ops)</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>     (iter-all-exp f ops nss `(,op ,e ,r))</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>     (if (not (exchangeable op))</div>
<div><span class="Apple-tab-span" style="white-space:pre">			</span> (iter-all-exp f ops nss `(,op ,r ,e)))))))))</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>(iter-all-exp (chkexp 24) `(+ &#8211; * /) `(3 4 6 8))</div>
<div></div>
<div>只有短短17行。原因在于，lisp本身的ast即是用数据结构表示的，因此根本不需要我做eval函数，也不需要画蛇添足的弄自定义算符，直接用系统算符上。显示，打印，都是现成的。需要写的只有主体逻辑。结果也很特别：</div>
<div></div>
<div>&gt; (* (- (* 3 4) <img src='http://shell909090.com/blog/wp-includes/images/smilies/icon_cool.gif' alt='8)' class='wp-smiley' /> 6) </div>
<div>&gt; (* (- 8 (/ 6 3)) 4) </div>
<div>&gt; (* (- (* 4 3) <img src='http://shell909090.com/blog/wp-includes/images/smilies/icon_cool.gif' alt='8)' class='wp-smiley' /> 6) </div>
<div>&gt; (* (/ (+ 4 <img src='http://shell909090.com/blog/wp-includes/images/smilies/icon_cool.gif' alt='8)' class='wp-smiley' /> 3) 6) </div>
<div>&gt; (/ 6 (/ 3 (+ 4 8))) </div>
<div>&gt; (/ (* (+ 4 <img src='http://shell909090.com/blog/wp-includes/images/smilies/icon_cool.gif' alt='8)' class='wp-smiley' /> 6) 3) </div>
<div>&gt; (* (+ (/ 8 4) 6) 3) </div>
<div>&gt; (* (- 8 (/ 6 3)) 4) </div>
<div>&gt; (* (* (- 8 6) 3) 4) </div>
<div>&gt; (* (* (- 8 6) 4) 3) </div>
<div>&gt; (* (/ (+ 8 4) 3) 6) </div>
<div>&gt; (/ 6 (/ 3 (+ 8 4))) </div>
<div>
<p>&gt; (/ (* (+ 8 4) 6) 3) </p></div>
<div>&gt; (* (+ (/ 8 4) 6) 3) </div>
<div>&gt; (* (* (- 8 6) 3) 4) </div>
<div>&gt; (* (* (- 8 6) 4) 3) </div>
<div></div>
<div>不但行数只有一半，速度也很让人吐血，比python快了近一倍，这是100次的结果。</div>
<div></div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>Evaluation took:</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>  1.379 seconds of real time</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>  1.372086 seconds of total run time (1.372086 user, 0.000000 system)</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>  [ Run times consist of 0.012 seconds GC time, and 1.361 seconds non-GC time. ]</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>  99.49% CPU</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>  3,628,800 forms interpreted</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>  4,127,047,350 processor cycles</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>  102,577,080 bytes consed</div>
<div></div>
<div># go #</div>
<div></div>
<div># lua #</div>
<div>lua的代码是所有语言中最罗嗦的，足足长达60行，超过python许多。</div>
<div></div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>function find_item(tbl, obj)</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>   for i, v in pairs(tbl) do</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>      if v == obj then return i end</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>   end</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>   return nil</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>end</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>function remove_duplicates (tbl)</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>   local newtbl = {}</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>   for i, v in pairs(tbl) do</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>      if find_item(newtbl, v) == nil then</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span> table.insert(newtbl, v)</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>      end</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>   end</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>   return newtbl</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>end</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>function fmt_exp (e)</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>   if type(e) ~= &#39;table&#39; then</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>      return tostring(e)</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>   else</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>      return &#39;(&#39; .. fmt_exp(e[3]) .. e[1] .. fmt_exp(e[4]) .. &#39;)&#39;</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>   end</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>end</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>function eval_exp (e)</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>   if type(e) ~= &#39;table&#39; then</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>      return tonumber(e)</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>   else</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>      return e[2](eval_exp(e[3]), eval_exp(e[4]))</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>   end</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>end</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>function chkexp (target)</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>   return function (e)</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>     if eval_exp(e) == target then</div>
<div><span class="Apple-tab-span" style="white-space:pre">			</span>print(fmt_exp(e))</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>     end</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>  end</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>end</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>function iter_all_exp (f, ops, ns, e)</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>   if table.maxn(ns) == 0 then return f(e) end</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>   for i, r in pairs(remove_duplicates(ns)) do</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>      table.remove(ns, find_item(ns, r))</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>      if e == nil then</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span> iter_all_exp(f, ops, ns, r)</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>      else</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span> for op, fp in pairs(ops) do</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>    iter_all_exp(f, ops, ns, {op, fp, e, r})</div>
<div>
<p><span class="Apple-tab-span" style="white-space:pre">		</span>    if find_item(exchangable, op) == nil then</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>       iter_all_exp(f, ops, ns, {op, fp, r, e})</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>    end</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span> end</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>      end</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>      table.insert(ns, r)</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>   end</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>end</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>exchangable = {&#39;+&#39;, &#39;*&#39;}</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>opts = {</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>   [&#39;+&#39;] = function (a, b) return a + b end,</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>   [&#39;-&#39;] = function (a, b) return a &#8211; b end,</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>   [&#39;*&#39;] = function (a, b) return a * b end,</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>   [&#39;/&#39;] = function (a, b) return a / b end,</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>}</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>iter_all_exp(chkexp(24), opts, {3, 4, 6, 8})</div>
<div></div>
<div>其实lua的代码很好看，自然语言风格，语言写出来后都能看懂。然而lua秉持了最小化内核的方针，死活不提供一些很常用的函数。我上来近15行全在写常用函数，查找某个值在表中的位置，还有除去表中的重复元素。实现下来，效率也不是特别高，基本和python相当。</div>
<div></div>
<div>&gt; real<span class="Apple-tab-span" style="white-space:pre">	</span>0m2.222s</div>
<div>&gt; user<span class="Apple-tab-span" style="white-space:pre">	</span>0m2.184s</div>
<div>&gt; sys<span class="Apple-tab-span" style="white-space:pre">	</span>0m0.000s</div>
<div></div>
]]></content:encoded>
			<wfw:commentRss>http://shell909090.com/blog/2012/05/%e8%af%ad%e8%a8%80%e7%9a%84%e6%95%88%e7%8e%87%e5%b7%ae%e5%bc%822/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>语言的效率差异1</title>
		<link>http://shell909090.com/blog/2012/05/%e8%af%ad%e8%a8%80%e7%9a%84%e6%95%88%e7%8e%87%e5%b7%ae%e5%bc%821/</link>
		<comments>http://shell909090.com/blog/2012/05/%e8%af%ad%e8%a8%80%e7%9a%84%e6%95%88%e7%8e%87%e5%b7%ae%e5%bc%821/#comments</comments>
		<pubDate>Sun, 13 May 2012 18:52:27 +0000</pubDate>
		<dc:creator>shell</dc:creator>
				<category><![CDATA[其他]]></category>

		<guid isPermaLink="false">http://shell909090.com/blog/?p=2172</guid>
		<description><![CDATA[# 问题 # 为了测试语言的效率，做一个正则解析。 预先说好，正则解析的问题是老板正在做的一个实际问题，我把其他和效率无关的部分去了。因此我接受“用法不正确”这样的反驳理由，但是不接受“这不是典型用例”的理由。我欢迎你指正我的用法错误，或者对语言不了解导致的效率低下，但是别来和我吵吵这种例子太特殊。另外，在调整代码和评估速度的时候，顺便注意一下代码行数。我知道用汇编逐行写和优化会很优秀，但是这对实际工作基本没有帮助。 问题是这样的： &#62; 有一个文本文件，每行两个数，要求解析出来这两个数。 我用python生成了数据，代码是这样的     with open(sys.argv[1], &#39;w&#39;) as fo:         for i in xrange(500000):             fo.write(&#39;%d %dn&#39; % (i, random.randint(0, 10000))) 正则分析速率，是个典型的CPU密集操作。对于非编译型语言而言(这里的编译是指正则表达式的解析预编译，实际上除了lisp还真没有编译型的，即使是go也是现场拿到正则进行解析的)，这主要是看正则库的实现效率。很多时候，语言的效率问题并不取决于语言本身，还取决于语言的库的实现。大部分情况下我们都不可能砍掉系统的库重新来一个，那还不如换一门语言。 # python # &#8230; <a href="http://shell909090.com/blog/2012/05/%e8%af%ad%e8%a8%80%e7%9a%84%e6%95%88%e7%8e%87%e5%b7%ae%e5%bc%821/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<div># 问题 #</div>
<div>为了测试语言的效率，做一个正则解析。</div>
<div>预先说好，正则解析的问题是老板正在做的一个实际问题，我把其他和效率无关的部分去了。因此我接受“用法不正确”这样的反驳理由，但是不接受“这不是典型用例”的理由。我欢迎你指正我的用法错误，或者对语言不了解导致的效率低下，但是别来和我吵吵这种例子太特殊。另外，在调整代码和评估速度的时候，顺便注意一下代码行数。我知道用汇编逐行写和优化会很优秀，但是这对实际工作基本没有帮助。</div>
<div>问题是这样的：</div>
<div></div>
<div>&gt; 有一个文本文件，每行两个数，要求解析出来这两个数。</div>
<div></div>
<div>我用python生成了数据，代码是这样的</div>
<div></div>
<div>    with open(sys.argv[1], &#39;w&#39;) as fo:</div>
<div>        for i in xrange(500000):</div>
<div>            fo.write(&#39;%d %dn&#39; % (i, random.randint(0, 10000)))</div>
<div></div>
<div>正则分析速率，是个典型的CPU密集操作。对于非编译型语言而言(这里的编译是指正则表达式的解析预编译，实际上除了lisp还真没有编译型的，即使是go也是现场拿到正则进行解析的)，这主要是看正则库的实现效率。很多时候，语言的效率问题并不取决于语言本身，还取决于语言的库的实现。大部分情况下我们都不可能砍掉系统的库重新来一个，那还不如换一门语言。</div>
<div></div>
<div># python #</div>
<div>我首先贴出python语言的解答。</div>
<div></div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>reline = re.compile(&#39;(d+) (d+)&#39;)</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>def main():</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>with open(sys.argv[1], &#39;r&#39;) as fi:</div>
<div><span class="Apple-tab-span" style="white-space:pre">			</span>for line in fi: reline.match(line).groups()</div>
<div></div>
<div>这是性能</div>
<div></div>
<div>&gt; real    0m0.466s</div>
<div>&gt; user    0m0.436s</div>
<div>&gt; sys     0m0.012s</div>
<div></div>
<div># common lisp #</div>
<div>我找了N个正则包，实际能用的只有ppcre。有些包号称很快，实际测试下来还不如ppcre。</div>
<div></div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>(require :cl-ppcre)</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>(defun grepfile (filename)</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>  (let* ((cl-ppcre:*use-bmh-matchers* t)</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span> (cl-ppcre:*regex-char-code-limit* 256)</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span> (scanner (cl-ppcre:create-scanner &quot;d+ d+&quot;)))</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>    (with-open-file (in filename)</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>      (loop for line = (read-line in nil) while line do</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>   (cl-ppcre:split scanner line)))</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>  ))</div>
<div></div>
<div>代码在slime里面测试(time (grepfile &quot;data.dat&quot;))，下面是结果</div>
<div></div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>CL-USER&gt; (time (main))</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>Evaluation took:</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>  0.398 seconds of real time</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>  0.392025 seconds of total run time (0.384024 user, 0.008001 system)</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>  [ Run times consist of 0.016 seconds GC time, and 0.377 seconds non-GC time. ]</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>  98.49% CPU</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>  1,188,481,425 processor cycles</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>  72,242,256 bytes consed</div>
<div></div>
<div># go #</div>
<div>go的代码是现学现卖的，不知道是不是哪里写出问题了。</div>
<div></div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>func main() {</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>f, _ := os.Open(&quot;data.txt&quot;)</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>r := bufio.NewReader(f)</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span></div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>rex, _ := regexp.Compile(&quot;(\d+) (\d+)&quot;)</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span></div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>for line, isPrefix, err := r.ReadLine();</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>    err == nil &amp;&amp; !isPrefix;</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>    line, isPrefix, err = r.ReadLine() {</div>
<div><span class="Apple-tab-span" style="white-space:pre">			</span>rex.FindSubmatch(line)</div>
<div><span class="Apple-tab-span" style="white-space:pre">		</span>}</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>}</div>
<div></div>
<div>结果居然要差一个数量级！</div>
<div></div>
<div>&gt; real<span class="Apple-tab-span" style="white-space:pre">	</span>0m8.699s</div>
<div> &gt; user<span class="Apple-tab-span" style="white-space:pre">	</span>0m8.593s</div>
<div>&gt; sys<span class="Apple-tab-span" style="white-space:pre">	</span>0m0.036s</div>
<div></div>
<div>这太出乎我的意料了。google的v8引擎赫赫有名，我猜想也应当用到了go上面才是，怎么会性能差成这样？gary说过正则在他那里很快，我希望是我用错了。</div>
<div></div>
<div># lua #</div>
<div>lua没有使用正则包，更准确的说，lua内置的字符串处理函数可以处理这个情况。以下是我的代码：</div>
<div></div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>for line in io.lines(&quot;data.txt&quot;) do</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>   for w in string.gmatch(line, &quot;%d+&quot;) do</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>      &#8211; print(w)</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>   end</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>end</div>
<div></div>
<div>以下是执行结果：</div>
<div></div>
<div>&gt; real<span class="Apple-tab-span" style="white-space:pre">	</span>0m0.796s</div>
<div>&gt; user<span class="Apple-tab-span" style="white-space:pre">	</span>0m0.792s</div>
<div>&gt; sys<span class="Apple-tab-span" style="white-space:pre">	</span>0m0.000s</div>
<div></div>
<div>lua的代码的却很好看，但是效率上却不见得高。这是当然的，gmatch可是每工作一次就要解析一次阿。</div>
<div></div>
<div># lua-rex-pcre #</div>
<div>装一个支持pcre的正则包，lua-rex-pcre。</div>
<div></div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>r = require &quot;rex_pcre&quot;.new(&quot;(\d+) (\d+)&quot;, 0)</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>for line in io.lines(&quot;data.txt&quot;) do</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>   r.match(r, line)</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>end</div>
<div></div>
<div>OK，速度一下就快了不少：</div>
<div></div>
<div> &gt; real<span class="Apple-tab-span" style="white-space:pre">	</span>0m0.643s</div>
<div>&gt; user<span class="Apple-tab-span" style="white-space:pre">	</span>0m0.632s</div>
<div>&gt; sys<span class="Apple-tab-span" style="white-space:pre">	</span>0m0.008s</div>
<div></div>
]]></content:encoded>
			<wfw:commentRss>http://shell909090.com/blog/2012/05/%e8%af%ad%e8%a8%80%e7%9a%84%e6%95%88%e7%8e%87%e5%b7%ae%e5%bc%821/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>新闻和八卦和概率聚集</title>
		<link>http://shell909090.com/blog/2012/05/%e6%96%b0%e9%97%bb%e5%92%8c%e5%85%ab%e5%8d%a6%e5%92%8c%e6%a6%82%e7%8e%87%e8%81%9a%e9%9b%86/</link>
		<comments>http://shell909090.com/blog/2012/05/%e6%96%b0%e9%97%bb%e5%92%8c%e5%85%ab%e5%8d%a6%e5%92%8c%e6%a6%82%e7%8e%87%e8%81%9a%e9%9b%86/#comments</comments>
		<pubDate>Thu, 10 May 2012 18:25:49 +0000</pubDate>
		<dc:creator>shell</dc:creator>
				<category><![CDATA[其他]]></category>

		<guid isPermaLink="false">http://shell909090.com/blog/?p=2170</guid>
		<description><![CDATA[新闻和八卦有个共同点，就是会扭曲我们常规的概率体验，例如：今天摔了一架飞机。我们的结论往往是，飞机好危险。然而，世界上有很多没问题的飞机，这个你是不会从新闻和八卦里面听到的。因此，以这些东西为基础得出的结论，往往是错的。 从这点说开去，其实我们会发现很多东西都不可靠。首先说八卦。八卦之不可靠是全世界皆知的，要是有人神神秘秘和你说个事情，要么是一点不着边的瞎猜，要么就是一枪命中的内幕。可惜的是，到底是哪个，在事先完全无法分辨。香农说，信息就是减少不确定性，从这点来说，这些八卦里面的信息量是负数——本来一个事情挺明白，八卦一传，搞不好当事人都不明白是怎么回事了。 其次我们再说新闻，新闻倒是有信息量，但是新闻的不可靠也是人尽皆知。中国的文艺宣传理论就不去说了，老美也经常骂，大新闻集团只挑符合他们利益的说。不过幸好，人家新闻利益集团有好几个，岳飞打张飞之下，总算还有不少东西给披露出来。 最后，你的亲眼所见一定是真么？我在以前的一篇blog里面说过，我对问题的分析是偏颇的，因为我做不到随机取样。我周围的朋友，一定是具备某个特性/符合某个范式的。例如熟悉电脑，受良好教育的城市青年，中国人，这些总是没办法的事情。如果以此为样本来分析相关问题，相信一定会南辕北辙。例如你以我的gtalk和twitter好友来分析python和emacs用户的比例，那一定是高的异乎寻常。这是当然的，我本来就是以python和emacs作为自己的标签，无论是朋友也好，会fo我的人也好，多半是此道同好。以此类推，若是你不仔细分析，即使以亲眼所见，也未必能得到结论。]]></description>
			<content:encoded><![CDATA[<div><span style="white-space:pre-wrap">	</span>新闻和八卦有个共同点，就是会扭曲我们常规的概率体验，例如：今天摔了一架飞机。我们的结论往往是，飞机好危险。然而，世界上有很多没问题的飞机，这个你是不会从新闻和八卦里面听到的。因此，以这些东西为基础得出的结论，往往是错的。</div>
<div><span style="white-space:pre-wrap">	</span>从这点说开去，其实我们会发现很多东西都不可靠。首先说八卦。八卦之不可靠是全世界皆知的，要是有人神神秘秘和你说个事情，要么是一点不着边的瞎猜，要么就是一枪命中的内幕。可惜的是，到底是哪个，在事先完全无法分辨。香农说，信息就是减少不确定性，从这点来说，这些八卦里面的信息量是负数——本来一个事情挺明白，八卦一传，搞不好当事人都不明白是怎么回事了。</div>
<div><span style="white-space:pre-wrap">	</span>其次我们再说新闻，新闻倒是有信息量，但是新闻的不可靠也是人尽皆知。中国的文艺宣传理论就不去说了，老美也经常骂，大新闻集团只挑符合他们利益的说。不过幸好，人家新闻利益集团有好几个，岳飞打张飞之下，总算还有不少东西给披露出来。</div>
<div><span style="white-space:pre-wrap">	</span>最后，你的亲眼所见一定是真么？我在以前的一篇blog里面说过，我对问题的分析是偏颇的，因为我做不到随机取样。我周围的朋友，一定是具备某个特性/符合某个范式的。例如熟悉电脑，受良好教育的城市青年，中国人，这些总是没办法的事情。如果以此为样本来分析相关问题，相信一定会南辕北辙。例如你以我的gtalk和twitter好友来分析python和emacs用户的比例，那一定是高的异乎寻常。这是当然的，我本来就是以python和emacs作为自己的标签，无论是朋友也好，会fo我的人也好，多半是此道同好。以此类推，若是你不仔细分析，即使以亲眼所见，也未必能得到结论。</div>
]]></content:encoded>
			<wfw:commentRss>http://shell909090.com/blog/2012/05/%e6%96%b0%e9%97%bb%e5%92%8c%e5%85%ab%e5%8d%a6%e5%92%8c%e6%a6%82%e7%8e%87%e8%81%9a%e9%9b%86/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>全部和谐音程表（泛音表）</title>
		<link>http://shell909090.com/blog/2012/05/%e5%85%a8%e9%83%a8%e5%92%8c%e8%b0%90%e9%9f%b3%e7%a8%8b%e8%a1%a8%ef%bc%88%e6%b3%9b%e9%9f%b3%e8%a1%a8%ef%bc%89/</link>
		<comments>http://shell909090.com/blog/2012/05/%e5%85%a8%e9%83%a8%e5%92%8c%e8%b0%90%e9%9f%b3%e7%a8%8b%e8%a1%a8%ef%bc%88%e6%b3%9b%e9%9f%b3%e8%a1%a8%ef%bc%89/#comments</comments>
		<pubDate>Wed, 09 May 2012 18:14:04 +0000</pubDate>
		<dc:creator>shell</dc:creator>
				<category><![CDATA[其他]]></category>

		<guid isPermaLink="false">http://shell909090.com/blog/?p=2168</guid>
		<description><![CDATA[&#62;&#62;&#62; for i in [(i, j, 12 * math.log(float(j)/i, 2)) for i, j in itertools.permutations([1,2,3,4,5,6], 2) if i &#60; j]: print i&#8230; (1, 2, 12.0)(1, 3, 19.019550008653876) (1, 4, 24.0)(1, 5, 27.863137138648348) (1, 6, 31.019550008653873)(2, 3, 7.019550008653875)(2, 4, 12.0)(2, 5, 15.863137138648348)(2, 6, &#8230; <a href="http://shell909090.com/blog/2012/05/%e5%85%a8%e9%83%a8%e5%92%8c%e8%b0%90%e9%9f%b3%e7%a8%8b%e8%a1%a8%ef%bc%88%e6%b3%9b%e9%9f%b3%e8%a1%a8%ef%bc%89/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>&gt;&gt;&gt; for i in [(i, j, 12 * math.log(float(j)/i, 2)) for i, j in itertools.permutations([1,2,3,4,5,6], 2) if i &lt; j]: print i<br />&#8230; <br />(1, 2, 12.0)<br />(1, 3, 19.019550008653876) <br />(1, 4, 24.0)<br />(1, 5, 27.863137138648348)</p>
<p> (1, 6, 31.019550008653873)<br />(2, 3, 7.019550008653875)<br />(2, 4, 12.0)<br />(2, 5, 15.863137138648348)<br />(2, 6, 19.019550008653876)<br />(3, 4, 4.980449991346124)<br />(3, 5, 8.843587129994475)<br />(3, 6, 12.0)<br />(4, 5, 3.863137138648348)</p>
<p> (4, 6, 7.019550008653875)<br />(5, 6, 3.1564128700055254)</p>
]]></content:encoded>
			<wfw:commentRss>http://shell909090.com/blog/2012/05/%e5%85%a8%e9%83%a8%e5%92%8c%e8%b0%90%e9%9f%b3%e7%a8%8b%e8%a1%a8%ef%bc%88%e6%b3%9b%e9%9f%b3%e8%a1%a8%ef%bc%89/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>论医</title>
		<link>http://shell909090.com/blog/2012/05/%e8%ae%ba%e5%8c%bb/</link>
		<comments>http://shell909090.com/blog/2012/05/%e8%ae%ba%e5%8c%bb/#comments</comments>
		<pubDate>Wed, 09 May 2012 01:09:01 +0000</pubDate>
		<dc:creator>shell</dc:creator>
				<category><![CDATA[其他]]></category>

		<guid isPermaLink="false">http://shell909090.com/blog/?p=2166</guid>
		<description><![CDATA[# 医生的道德标准 # 要摆正医患关系，首先就必须将医生的道德标准降下来，从“白求恩精神”，降低到一般人标准。 为什么？有一则故事，叫做“子贡赎人”，挺有名的，大家可以自查。跳过故事本身，我直接说其中的观点： 如果将道德标准提高到没有人能够接受的地步，就不会有人照做了。 类似，大家都是人，为什么让别人去遵循“白求恩精神”，或者其他变态的精神，而让自己能够得利呢？拥有这种精神的毕竟是少数。以这个为标准要求多数人的结果，就是没有人能够成为医生。 医生的标准，只要能够诚实的提供服务就好了。动辄就拿奉献说事，实则是用大帽子压人，和文革无异。         当然，现今最主要的问题，是以白求恩精神要求医生的同时，连诚实服务都贯彻不下去。这种动辄涉及人命的事情上不公开透明是会出人命的。只要有一小撮是贯彻不下去的，那病人就会连剩下的医生一并怀疑，然后杀医生的戏码就会层出不穷。 貌似要立法阻止杀医什么的，其实我说，这也就是对纯粹的医闹管用，真的爆上新闻的，多半不会是医闹。道理很简单，医闹的目的是拿钱，耍赖撒泼软语哀求的目的都是拿钱而不是报仇。就算他再和医生横眉竖眼，也不会往死里下手——真的往死里整的，多半是豁出一条命的家伙。人不畏死，奈何以死惧之。解决这个问题的最好途径不是阻拦，而是有个心平气和能让他解决问题的途径。 # 不实施抢救的道德标准 # 我认为，以下两种情况下，不实施抢救不应当受到责难。 1. 病人死亡。 2. 病人不可避免的向死亡发展，其中会为本人或家属带来极大痛苦。 # 医疗会耗尽社会的剩余资源 # 我觉得这是不言自明的。人类社会从原始社会仅够自己温饱，发展到目前的状态。实则目前一个人的工作供养数人足矣。或者换个表达方式，全球所有人所需的食物/衣物/住房等资源，并不需要所有的人类进行生产。若非如此，贫困救助体系和养老体系都没有发展的前提。多余的人产生的物资，即是社会的剩余资源。 社会目前的剩余资源，必然会有一个出口。一方面，第三产业，娱乐业，都是基于剩余资源的。也可以看作，从事生产的人为他们提供食粮，而他们为从事生产的人带来娱乐。而另一方面，科技发展，医疗和医疗技术发展，也是基于这些资源的。 随着科技发展，人类的剩余资源冗余度会越来越大。人类需要的必需品只需要更少的人进行生产，更多的人会投身非直接产生必需品的行业。在这种情况下，我更希望他们参与医疗和科技发展。并不是说娱乐业不好，或者不需要。只是科技和医疗能够带给人更好的生活——我是这么相信的。]]></description>
			<content:encoded><![CDATA[<div># 医生的道德标准 #</div>
<div><span style="white-space:pre-wrap">	</span>要摆正医患关系，首先就必须将医生的道德标准降下来，从“白求恩精神”，降低到一般人标准。</div>
<div><span style="white-space:pre-wrap">	</span>为什么？有一则故事，叫做“子贡赎人”，挺有名的，大家可以自查。跳过故事本身，我直接说其中的观点：</div>
<div><span style="white-space:pre-wrap">	</span>如果将道德标准提高到没有人能够接受的地步，就不会有人照做了。</div>
<div><span style="white-space:pre-wrap">	</span>类似，大家都是人，为什么让别人去遵循“白求恩精神”，或者其他变态的精神，而让自己能够得利呢？拥有这种精神的毕竟是少数。以这个为标准要求多数人的结果，就是没有人能够成为医生。</div>
<div><span style="white-space:pre-wrap">	</span>医生的标准，只要能够诚实的提供服务就好了。动辄就拿奉献说事，实则是用大帽子压人，和文革无异。</div>
<div>        当然，现今最主要的问题，是以白求恩精神要求医生的同时，连诚实服务都贯彻不下去。这种动辄涉及人命的事情上不公开透明是会出人命的。只要有一小撮是贯彻不下去的，那病人就会连剩下的医生一并怀疑，然后杀医生的戏码就会层出不穷。</div>
<div><span style="white-space:pre-wrap">	</span>貌似要立法阻止杀医什么的，其实我说，这也就是对纯粹的医闹管用，真的爆上新闻的，多半不会是医闹。道理很简单，医闹的目的是拿钱，耍赖撒泼软语哀求的目的都是拿钱而不是报仇。就算他再和医生横眉竖眼，也不会往死里下手——真的往死里整的，多半是豁出一条命的家伙。人不畏死，奈何以死惧之。解决这个问题的最好途径不是阻拦，而是有个心平气和能让他解决问题的途径。</div>
<div></div>
<div># 不实施抢救的道德标准 #</div>
<div><span style="white-space:pre-wrap">	</span>我认为，以下两种情况下，不实施抢救不应当受到责难。</div>
<div>1. 病人死亡。</div>
<div>2. 病人不可避免的向死亡发展，其中会为本人或家属带来极大痛苦。</div>
<div></div>
<div># 医疗会耗尽社会的剩余资源 #</div>
<div><span style="white-space:pre-wrap">	</span>我觉得这是不言自明的。人类社会从原始社会仅够自己温饱，发展到目前的状态。实则目前一个人的工作供养数人足矣。或者换个表达方式，全球所有人所需的食物/衣物/住房等资源，并不需要所有的人类进行生产。若非如此，贫困救助体系和养老体系都没有发展的前提。多余的人产生的物资，即是社会的剩余资源。</div>
<div><span style="white-space:pre-wrap">	</span>社会目前的剩余资源，必然会有一个出口。一方面，第三产业，娱乐业，都是基于剩余资源的。也可以看作，从事生产的人为他们提供食粮，而他们为从事生产的人带来娱乐。而另一方面，科技发展，医疗和医疗技术发展，也是基于这些资源的。</div>
<div><span style="white-space:pre-wrap">	</span>随着科技发展，人类的剩余资源冗余度会越来越大。人类需要的必需品只需要更少的人进行生产，更多的人会投身非直接产生必需品的行业。在这种情况下，我更希望他们参与医疗和科技发展。并不是说娱乐业不好，或者不需要。只是科技和医疗能够带给人更好的生活——我是这么相信的。</div>
<div></div>
]]></content:encoded>
			<wfw:commentRss>http://shell909090.com/blog/2012/05/%e8%ae%ba%e5%8c%bb/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>升调降调的规则</title>
		<link>http://shell909090.com/blog/2012/05/%e5%8d%87%e8%b0%83%e9%99%8d%e8%b0%83%e7%9a%84%e8%a7%84%e5%88%99/</link>
		<comments>http://shell909090.com/blog/2012/05/%e5%8d%87%e8%b0%83%e9%99%8d%e8%b0%83%e7%9a%84%e8%a7%84%e5%88%99/#comments</comments>
		<pubDate>Mon, 07 May 2012 01:21:06 +0000</pubDate>
		<dc:creator>shell</dc:creator>
				<category><![CDATA[其他]]></category>

		<guid isPermaLink="false">http://shell909090.com/blog/?p=2164</guid>
		<description><![CDATA[    为什么C加一个升调变成G？     这个要从大调式讲起。     大调式是以大三度为基础构建的调式，主音到中音为大三度，中音到属音为小三度，两者构成大三和弦。主音到属音为纯五度，属音到主音为纯四度，大调式的三个基础音之间，都是和谐音程关系。以C大调而言，就是do mi so。     好吧，C大调之所以叫做C大调，是因为以中音C为do。那么G大调呢？以中音G为do？对的，问题是，C大调的所有音，是否能够不做任何变化的构成G大调的音？     这是不可能的，C大调的音不做变化唯一能够构成的只有a小调。G大调一定需要对C大调的音做升降的。     为什么？因为C大调的音程关系是全全半全全全半，这个在小学就教了。通过这个，你可以数出上面说的三个纯音关系。当我们位移到G=do的时候，你会发现，不做变化的话，音程就变成了全全半全全半全，这就糟了。所以，需要对C调的fa(即F)升半个音，来回复大调调式。     常识上我们知道，12平均率是对称关系，所以上述过程可以运用数学归纳法作用于整个中音音阶。即，每个大调可以通过升该调中的fa半个音，变成另一个大调。后者刚刚好比前者高一个纯五度。     降调关系亦然，可以类比。     小调关系亦然，不过小调使用全半全全半全全作为结构，主音到中音为小三度，中音到属音为大三度，两者构成小三和弦。主音到属音为纯五度，属音到主音为纯四度，小调式的三个基础音之间，也都是和谐音程关系。     稍微数一下就知道，小调式上的所有音，可以构成比自己高小三度的大调，两者称为关系大调和关系小调。     虽然音是一样的，然而主音中音属音的位置完全不同，因此调式色彩完全不同。]]></description>
			<content:encoded><![CDATA[<p>    为什么C加一个升调变成G？
<div>    这个要从大调式讲起。</div>
<div>    大调式是以大三度为基础构建的调式，主音到中音为大三度，中音到属音为小三度，两者构成大三和弦。主音到属音为纯五度，属音到主音为纯四度，大调式的三个基础音之间，都是和谐音程关系。以C大调而言，就是do mi so。</div>
<div>    好吧，C大调之所以叫做C大调，是因为以中音C为do。那么G大调呢？以中音G为do？对的，问题是，C大调的所有音，是否能够不做任何变化的构成G大调的音？</div>
<div>    这是不可能的，C大调的音不做变化唯一能够构成的只有a小调。G大调一定需要对C大调的音做升降的。</div>
<div>    为什么？因为C大调的音程关系是全全半全全全半，这个在小学就教了。通过这个，你可以数出上面说的三个纯音关系。当我们位移到G=do的时候，你会发现，不做变化的话，音程就变成了全全半全全半全，这就糟了。所以，需要对C调的fa(即F)升半个音，来回复大调调式。</div>
<div>    常识上我们知道，12平均率是对称关系，所以上述过程可以运用数学归纳法作用于整个中音音阶。即，每个大调可以通过升该调中的fa半个音，变成另一个大调。后者刚刚好比前者高一个纯五度。</div>
<div>    降调关系亦然，可以类比。</div>
<div>    小调关系亦然，不过小调使用全半全全半全全作为结构，主音到中音为小三度，中音到属音为大三度，两者构成小三和弦。主音到属音为纯五度，属音到主音为纯四度，小调式的三个基础音之间，也都是和谐音程关系。</div>
<div>    稍微数一下就知道，小调式上的所有音，可以构成比自己高小三度的大调，两者称为关系大调和关系小调。</div>
<div>    虽然音是一样的，然而主音中音属音的位置完全不同，因此调式色彩完全不同。</div>
]]></content:encoded>
			<wfw:commentRss>http://shell909090.com/blog/2012/05/%e5%8d%87%e8%b0%83%e9%99%8d%e8%b0%83%e7%9a%84%e8%a7%84%e5%88%99/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>关于翻墙服务几句</title>
		<link>http://shell909090.com/blog/2012/05/%e5%85%b3%e4%ba%8e%e7%bf%bb%e5%a2%99%e6%9c%8d%e5%8a%a1%e5%87%a0%e5%8f%a5/</link>
		<comments>http://shell909090.com/blog/2012/05/%e5%85%b3%e4%ba%8e%e7%bf%bb%e5%a2%99%e6%9c%8d%e5%8a%a1%e5%87%a0%e5%8f%a5/#comments</comments>
		<pubDate>Thu, 03 May 2012 18:09:39 +0000</pubDate>
		<dc:creator>shell</dc:creator>
				<category><![CDATA[其他]]></category>

		<guid isPermaLink="false">http://shell909090.com/blog/?p=2162</guid>
		<description><![CDATA[    目前有很多服务，其实我们都是按照非正规用法在用的。例如github，看上去像是个源码托管服务，我们拿来当blog用。GAE，看上去像是个代码托管服务，我们当翻墙工具用。空间，常规都是发布应用的，我们也拿来翻墙。     对服务的非正规用法，我们首先把这个命题分几个类。一类是服务本身没有对用法做出特殊假定，但是你的用法和传统用法相违背，例如VPS传统是作为私有主机用的，用于发布网站。但是天朝人民经常用VPS当作云存储，或者是VPN。作为这类用途，我觉得是没有任何问题的，服务商本身就没有限定你的应用类型。     第二类，是服务商默许或者半鼓励你作为特殊用途应用。例如github并不反对你用他作为blog。这也没问题。     第三类，服务商明确反对的用途。例如利用空间来翻墙。一来ssh流量并不计入你的流量限额中，二来长期使用空间翻墙会导致空间的服务器地址在中国被封。前者影响成本，后者影响销售。因此，很多空间商都封锁了ssh的跳板功能，例如DreamHost。     也许有人会骂，空间商为什么要阻止ssh，这是对自由人权的破坏什么的。我觉得这压根是骂错人了。如果你无法自由浏览你想要浏览的网页，你需要骂的是阻止你访问的人，而不是别人。空间商既没有封你，也不是帮凶。通过对人有害的方法获得自己想要的利益，别人阻止你还骂人，这是流氓嘴脸。     第四类，服务商没有明确回应，他们可能对此一无所知。这种情况最复杂，也最值得讨论。     无论空间商默许还是反对，我们都可以看作是一个附加合同。这种事情你同意就接着用，不同意就换家人，市场经济大家好聚好散。但是服务商没有明确回应，那么事情就比较暧昧。我倾向于将事情分为两个阶段，或者类型。一类是影响较小，或者刚刚出现，服务商有理由不知道。这种阶段下，该怎么用就怎么用。直到服务商有表态为止。另一类是我们有理由相信服务商知道这类用法。在这种阶段下，你不妨参照第二类。     当然，这里顺便说另外一个话题，就是很多人对翻墙的要求是——免费。     我去阿，你在中国网络上玩多了，啥都要免费，有没有写信给电信要求宽带接入免费阿。你要是真没钱，要么就不用，要么就学学怎么让自己出去。     天下的特权有几类的，一种是你通过努力来获得某种特权，一种是你付钱让别人帮你获得这种特权，一种是左求右拜，借到某种特权。这特权还不稳固，有点问题就让人收了回去，因此不得不小心翼翼，缩着尾巴做人。且不提现实中有个头痛脑热，行政手续，求爷爷告奶奶的诸多无奈。那毕竟很多时候还是不得以而为之。网络上凡是有点大小P事，全是“360度冰天雪地裸体跪求”，就这种人还自诩为“不食嗟来之食”之后，实在让人叹息。     墙的存在意义，就是要“拦截大多数”。要稳定翻墙，基本就两种途径。一者是牛，自己付出辛苦，学会了整个过程，从而翻墙出去。或者你付钱，弄到了翻墙帐号，从而翻墙出去，这也是一种。这两者都算的上少数，剩下的就是绝对的大多数。既不付钱，也不想付出辛苦，张口就求各种方法的人不知有没有想过，当某种方法会的人多了，墙自然就会把这种方法连根铲掉。法子不能用了，瞬间破口大骂给法子的人，不知道脑子里转的是什么逻辑——或者是，他们其实想过，只是： 1. 在中国，只要考虑三天后的事情，三个月后的事情谁说的准呢。 2. 在网络上求爷爷告奶奶也是一种辛苦阿。     ——我已经连叹息都发不出了。 &#8230; <a href="http://shell909090.com/blog/2012/05/%e5%85%b3%e4%ba%8e%e7%bf%bb%e5%a2%99%e6%9c%8d%e5%8a%a1%e5%87%a0%e5%8f%a5/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<div>    目前有很多服务，其实我们都是按照非正规用法在用的。例如github，看上去像是个源码托管服务，我们拿来当blog用。GAE，看上去像是个代码托管服务，我们当翻墙工具用。空间，常规都是发布应用的，我们也拿来翻墙。</div>
<div>    对服务的非正规用法，我们首先把这个命题分几个类。一类是服务本身没有对用法做出特殊假定，但是你的用法和传统用法相违背，例如VPS传统是作为私有主机用的，用于发布网站。但是天朝人民经常用VPS当作云存储，或者是VPN。作为这类用途，我觉得是没有任何问题的，服务商本身就没有限定你的应用类型。</div>
<div>    第二类，是服务商默许或者半鼓励你作为特殊用途应用。例如github并不反对你用他作为blog。这也没问题。</div>
<div>    第三类，服务商明确反对的用途。例如利用空间来翻墙。一来ssh流量并不计入你的流量限额中，二来长期使用空间翻墙会导致空间的服务器地址在中国被封。前者影响成本，后者影响销售。因此，很多空间商都封锁了ssh的跳板功能，例如DreamHost。</div>
<div>    也许有人会骂，空间商为什么要阻止ssh，这是对自由人权的破坏什么的。我觉得这压根是骂错人了。如果你无法自由浏览你想要浏览的网页，你需要骂的是阻止你访问的人，而不是别人。空间商既没有封你，也不是帮凶。通过对人有害的方法获得自己想要的利益，别人阻止你还骂人，这是流氓嘴脸。</div>
<div>    第四类，服务商没有明确回应，他们可能对此一无所知。这种情况最复杂，也最值得讨论。</div>
<div>    无论空间商默许还是反对，我们都可以看作是一个附加合同。这种事情你同意就接着用，不同意就换家人，市场经济大家好聚好散。但是服务商没有明确回应，那么事情就比较暧昧。我倾向于将事情分为两个阶段，或者类型。一类是影响较小，或者刚刚出现，服务商有理由不知道。这种阶段下，该怎么用就怎么用。直到服务商有表态为止。另一类是我们有理由相信服务商知道这类用法。在这种阶段下，你不妨参照第二类。</div>
<div></div>
<div>    当然，这里顺便说另外一个话题，就是很多人对翻墙的要求是——免费。</div>
<div>    我去阿，你在中国网络上玩多了，啥都要免费，有没有写信给电信要求宽带接入免费阿。你要是真没钱，要么就不用，要么就学学怎么让自己出去。</div>
<div>    天下的特权有几类的，一种是你通过努力来获得某种特权，一种是你付钱让别人帮你获得这种特权，一种是左求右拜，借到某种特权。这特权还不稳固，有点问题就让人收了回去，因此不得不小心翼翼，缩着尾巴做人。且不提现实中有个头痛脑热，行政手续，求爷爷告奶奶的诸多无奈。那毕竟很多时候还是不得以而为之。网络上凡是有点大小P事，全是“360度冰天雪地裸体跪求”，就这种人还自诩为“不食嗟来之食”之后，实在让人叹息。</div>
<div>    墙的存在意义，就是要“拦截大多数”。要稳定翻墙，基本就两种途径。一者是牛，自己付出辛苦，学会了整个过程，从而翻墙出去。或者你付钱，弄到了翻墙帐号，从而翻墙出去，这也是一种。这两者都算的上少数，剩下的就是绝对的大多数。既不付钱，也不想付出辛苦，张口就求各种方法的人不知有没有想过，当某种方法会的人多了，墙自然就会把这种方法连根铲掉。法子不能用了，瞬间破口大骂给法子的人，不知道脑子里转的是什么逻辑——或者是，他们其实想过，只是：</div>
<div>1. 在中国，只要考虑三天后的事情，三个月后的事情谁说的准呢。</div>
<div>2. 在网络上求爷爷告奶奶也是一种辛苦阿。</div>
<div>    ——我已经连叹息都发不出了。</div>
<div></div>
<div>    最后一个话题，如果你的某种对服务的应用，对其他人会产生伤害怎么办？例如，你用某个空间翻墙，这个空间IP就可能被墙。你用GAE翻墙，GAE就会被墙。你在网站上发表很合理的言论，自己没事，站长进去了。</div>
<div>    首先请允许我就最后一个例子向中国的有关部门表示无比的XXX。。。就这精确度还好意思指责人家老美的导弹？</div>
<div>    我们先说最后一个。很多人往往鄙视中国的网站管理者，我写个无比正常的内容你都给我删了。实际上，在一切不正常都当作正常的国度，再正常的内容都可能是不正常的。我是挺同情网站的管理者的，删把，道义上挺站不住的，不删吧，自己进去了。某种意义上说，开网站是为了赚两个钱顺便提供娱乐的(当然，很多人是反过来的)，而不是为你表达言论挺身而出的——真是这个目的开的网站现在站长的骨头都在长草了——从这个意义看，删，不是恶。如果你要指责，应当指责的是这个制度和产生这个制度的原因。</div>
<div>    但是，我又要但是了，这也有个度。删本身不是恶，但是捕风捉影，删了不说，不删，偷偷让别人看不到，这就沦为不道德了。只是在中国，各种事情交错纠缠之下，人人皆提心吊胆提防别人，往往事情就会走了样。</div>
<div>    这里插一个前两天的段子。魔都地铁是要安检的，大家知道。坐地铁的经常听说保安和你争执两句就躺地上装死讹钱的例子。前两天过地铁的时候，把包拿给保安检查。保安摸到我的饭盒，说，这是啥阿。我刚要说话，旁边保安示意放行，小声说，摸坏了你赔不起。</div>
<div>    ——那地铁安检的结果就不言自明了。</div>
<div>    因此，在层层把关的网络审查中，往往下层执行的东西和上层想的差了十万八千里。其距离大概就和客户心里的网站和项目经理笔下的网站和工程师手下的代码的区别差不多。</div>
<div>    当然，即便结论如此，我还是管我自己。我的blog都是在自己的域名下面——结果被封，也是自己的选择。如果发到其他网站，能不能留，留多久，就看别人的意思了。</div>
<div>
<p>    至于使用GAE翻墙的问题，我觉得适用于我们有理由相信服务商知道的情况。我相信Google一定知道上面有人放什么网站，做翻墙用途。既然他没有反对，我们可以看作是他默许。</p></div>
]]></content:encoded>
			<wfw:commentRss>http://shell909090.com/blog/2012/05/%e5%85%b3%e4%ba%8e%e7%bf%bb%e5%a2%99%e6%9c%8d%e5%8a%a1%e5%87%a0%e5%8f%a5/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>dvc和vc简评</title>
		<link>http://shell909090.com/blog/2012/05/dvc%e5%92%8cvc%e7%ae%80%e8%af%84/</link>
		<comments>http://shell909090.com/blog/2012/05/dvc%e5%92%8cvc%e7%ae%80%e8%af%84/#comments</comments>
		<pubDate>Wed, 02 May 2012 19:28:18 +0000</pubDate>
		<dc:creator>shell</dc:creator>
				<category><![CDATA[其他]]></category>

		<guid isPermaLink="false">http://shell909090.com/blog/?p=2160</guid>
		<description><![CDATA[# 我有必要换git么 # 实话说，这得分干吗。目前的推荐是，如果是企业级项目，对权限要求比较严格，你必须用svn。如果是普通项目，你可以尝试使用git，但是这并不表示git是最适合你项目的。有的时候svn比git合用的多。 # svn是什么模式 # svn的核心思路是，取出，修改，提交，合并。即，你从核心库中取得数据，修改，然后提交上去。如果有两个一样的修改，那么要求你进行合并。当然，svn工具会首先尝试自动合并，然后再让你手工干。但即使如此，合并的时候还是很费力。 svn的模式很容易理解，然而在使用中却有两个实际缺陷。 1. 保存数据的唯一方式就是提交，而提交是不可撤销的。 2. 必须连接核心库使用。 第一点问题，就是说，如果你希望暂时保存一下当前的修改状态，然后进行某个测试性修改。如果失败，退回当前。抱歉，做不到。你的提交一定会进入svn库。虽然你可以退回到你提交前的版本，但是很麻烦，而且版本记录不会消失。而第二个问题更加致命。如果在网络不稳定/没网络的时候，还干不干活了？ 因此，svn的设计模式并不鼓励你提交。当你有修改的时候，你必须保持修改的状态，直到某个稳定的状态。你需要检查代码是基本可用的，然后才应当提交。svn提交有个基础原则，不能塞住head，讲的就是这个。 # 所以有了hg # hg正是为了解决上述问题而出现的。hg实际上是用python实现的，解决上两个问题的svn。 hg拥有本地版本库，这解决了离线模式。至于暂存性提交，你可以在本地随便提交。只要不提交到核心库上，就不会导致塞住。如果你觉得本地库不行，可以直接重新co，而不进行push。 # git和hg哪个好 # 锤子和扳手哪个好？我永远无法回答你这个问题，因为这两个的目标根本不同，因此根本没有可比性。同样，git和hg的工作流程和模式完全是两回事，因此不要问这个问题，没意义。 # 哦，那么git是 # git的设计核心思路，是取出，分支，修改，提交，合并分支。git的分支是处理工作的利器。 要彻底理解git，你必须接受平行世界假定。假设世界并不是顺序发展的，由于你的选择不同，而会变成不同的几个分支。git可以让你在分支间自由穿越，并且让世界变成某个分支上的某个点的状态。你可以重新选择，产生一个不同的分支。当你需要时，可以对两个分支进行合并。如果两个分支从源头分开后，对世界的影响各自不同，那么合并就是自动的。 git的同步就是在同步这颗世界树。树扩展成什么样子和你在树的什么位置没有关系，因此fetch后如果不chechout，那么就不会应用最新的修改。 # 我没看出多大区别 # 实际是非常大的。有了平行世界假定，我可以正交的对一个源码做两件以上不同的事情。而在hg中，虽然也可以做两个不同的分支，然而却很难在两个分支间切换，从而使得切换到做另一件事情非常困难。这也导致了一个人实际上只能做一件事情，否则就无法将过程同时纳入vc管理，又满足正交。]]></description>
			<content:encoded><![CDATA[<div># 我有必要换git么 #</div>
<div>实话说，这得分干吗。目前的推荐是，如果是企业级项目，对权限要求比较严格，你必须用svn。如果是普通项目，你可以尝试使用git，但是这并不表示git是最适合你项目的。有的时候svn比git合用的多。</div>
<div></div>
<div># svn是什么模式 #</div>
<div>svn的核心思路是，取出，修改，提交，合并。即，你从核心库中取得数据，修改，然后提交上去。如果有两个一样的修改，那么要求你进行合并。当然，svn工具会首先尝试自动合并，然后再让你手工干。但即使如此，合并的时候还是很费力。</div>
<div>svn的模式很容易理解，然而在使用中却有两个实际缺陷。</div>
<div></div>
<div>1. 保存数据的唯一方式就是提交，而提交是不可撤销的。</div>
<div>2. 必须连接核心库使用。</div>
<div></div>
<div>第一点问题，就是说，如果你希望暂时保存一下当前的修改状态，然后进行某个测试性修改。如果失败，退回当前。抱歉，做不到。你的提交一定会进入svn库。虽然你可以退回到你提交前的版本，但是很麻烦，而且版本记录不会消失。而第二个问题更加致命。如果在网络不稳定/没网络的时候，还干不干活了？</div>
<div>因此，svn的设计模式并不鼓励你提交。当你有修改的时候，你必须保持修改的状态，直到某个稳定的状态。你需要检查代码是基本可用的，然后才应当提交。svn提交有个基础原则，不能塞住head，讲的就是这个。</div>
<div></div>
<div># 所以有了hg #</div>
<div>hg正是为了解决上述问题而出现的。hg实际上是用python实现的，解决上两个问题的svn。</div>
<div>hg拥有本地版本库，这解决了离线模式。至于暂存性提交，你可以在本地随便提交。只要不提交到核心库上，就不会导致塞住。如果你觉得本地库不行，可以直接重新co，而不进行push。</div>
<div></div>
<div># git和hg哪个好 #</div>
<div>锤子和扳手哪个好？我永远无法回答你这个问题，因为这两个的目标根本不同，因此根本没有可比性。同样，git和hg的工作流程和模式完全是两回事，因此不要问这个问题，没意义。</div>
<div></div>
<div># 哦，那么git是 #</div>
<div>git的设计核心思路，是取出，分支，修改，提交，合并分支。git的分支是处理工作的利器。</div>
<div>要彻底理解git，你必须接受平行世界假定。假设世界并不是顺序发展的，由于你的选择不同，而会变成不同的几个分支。git可以让你在分支间自由穿越，并且让世界变成某个分支上的某个点的状态。你可以重新选择，产生一个不同的分支。当你需要时，可以对两个分支进行合并。如果两个分支从源头分开后，对世界的影响各自不同，那么合并就是自动的。</div>
<div>git的同步就是在同步这颗世界树。树扩展成什么样子和你在树的什么位置没有关系，因此fetch后如果不chechout，那么就不会应用最新的修改。</div>
<div></div>
<div># 我没看出多大区别 #</div>
<div>实际是非常大的。有了平行世界假定，我可以正交的对一个源码做两件以上不同的事情。而在hg中，虽然也可以做两个不同的分支，然而却很难在两个分支间切换，从而使得切换到做另一件事情非常困难。这也导致了一个人实际上只能做一件事情，否则就无法将过程同时纳入vc管理，又满足正交。</div>
<div></div>
]]></content:encoded>
			<wfw:commentRss>http://shell909090.com/blog/2012/05/dvc%e5%92%8cvc%e7%ae%80%e8%af%84/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>首次bsp日记</title>
		<link>http://shell909090.com/blog/2012/05/%e9%a6%96%e6%ac%a1bsp%e6%97%a5%e8%ae%b0/</link>
		<comments>http://shell909090.com/blog/2012/05/%e9%a6%96%e6%ac%a1bsp%e6%97%a5%e8%ae%b0/#comments</comments>
		<pubDate>Tue, 01 May 2012 19:09:03 +0000</pubDate>
		<dc:creator>shell</dc:creator>
				<category><![CDATA[其他]]></category>

		<guid isPermaLink="false">http://shell909090.com/blog/?p=2158</guid>
		<description><![CDATA[第一次参加BSP，还不错拉。因为以前没参加过，所以等搞明白了这个是干吗的再和大家说。 BSP是bug squeeze party的简称，简单来说就是修错会。debian马上要发行7了，在此之前有很多的bug没有修复。其中有一种是RC bug，即运行就会出大问题的bug，或者干脆没法编译。无论哪个，都会导致这个包不能进入最新的发布。有些bug很麻烦，需要maintainer和author沟通，这个没有办法。但是有些问题解决起来很简单，只是因为后果很严重，作者又暂时没空处理，导致包无法进入stable，实在很无谓。BSP的目的，主要是以非维护者上传(non-maintainer upload)的方式修复这类bug。因为包不是自己的，所以礼貌上，只修复半个月以上的rc级别bug，其他的留给maintainer来处理。 BSP的主要目的，就是这么一个苦力会。没有挂名，最多只有一条changelog记录，还要大量寻找和修复bug。不过BSP相当重要，因为很多maintainer往往有一段一段的不活跃时间。这时候即使再简单的问题也不会处理。按照debian的规则，别人也不会帮他处理。除了BSP，很少有一批人会专门找这种简单的Bug来修正。如果没有BSP，debian stable发布的时候一做RC冻结，就要少掉很多有用的包。BSP更大的目的是，交流和传授debian打包和除错的经验，唤起人们的关注。也许在会后，如果有人看到一些简单bug，会使用nmu的方法给与修正。不过BSP到确实是有一个额外加成的好处——基本变成了签名会。昨天估计是中国大陆地区首次DD数量接近其他人数量，我一下弄到了5个签名，2个DD一个Ubuntu员工。加上原来就有的zigo签名，我就有3个DD签名了。 本地BSP是在thomas的公司举行，欧特家博士匹萨厂商赞助了我们两天的午餐——微波食品匹萨。第一天来的人比较多，很多都是纯新手，大概有20多人。Zigo倒是在网络上说会帮助新手，但是纯新手看到debian打包系统根本无从下手，所谓指导什么的也无从说起。很多人一天一个bug都修不掉，甚至都看不懂，很有挫折感，估计有不少有热情的人在第二天就这么默默退散了，第二天只来了15个左右。 我主要是以修复自己的问题为主，python-snappy和python-formalchemy都升级到了最高级，并且修复了自己以前打包的一个问题。至于RC bug么，我修了一个。两个包在python中命名冲突了，所以在debian中需要声明为conflicts。另外我评审了一下，最终还是决定关闭了python-libmemcached的ITP。虽然对douban很不好意思，还让他们修了一下。但是python-libmemcached依赖于libmemcached，而后者已经逐步升级到了1.0.X版本，但是douban为了稳定使用，是sticky在0.4版上的。因此当更新的debian发行时，实际上python-libmemcached和系统中的libmemcached不是一回事。因此，我不能依赖libmemcached的维护者，而是需要自己去维护后者——没办法，我就是怂了。python-libmemcached的爱用者，还是自己打包吧。我倒是可以公开打包文档。 另外，我在想是否要集合一批python/debian的用户，来做投票。例如，python的一个容器——flup，在debian中实际上已经orphon了。如果有足够的人投票，我愿意为flup做接手维护工作。不过目前debian下问下来的结果，大家对flup没什么太大兴趣。]]></description>
			<content:encoded><![CDATA[<div><span class="Apple-tab-span" style="white-space:pre">	</span>第一次参加BSP，还不错拉。因为以前没参加过，所以等搞明白了这个是干吗的再和大家说。</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>BSP是bug squeeze party的简称，简单来说就是修错会。debian马上要发行7了，在此之前有很多的bug没有修复。其中有一种是RC bug，即运行就会出大问题的bug，或者干脆没法编译。无论哪个，都会导致这个包不能进入最新的发布。有些bug很麻烦，需要maintainer和author沟通，这个没有办法。但是有些问题解决起来很简单，只是因为后果很严重，作者又暂时没空处理，导致包无法进入stable，实在很无谓。BSP的目的，主要是以非维护者上传(non-maintainer upload)的方式修复这类bug。因为包不是自己的，所以礼貌上，只修复半个月以上的rc级别bug，其他的留给maintainer来处理。</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>BSP的主要目的，就是这么一个苦力会。没有挂名，最多只有一条changelog记录，还要大量寻找和修复bug。不过BSP相当重要，因为很多maintainer往往有一段一段的不活跃时间。这时候即使再简单的问题也不会处理。按照debian的规则，别人也不会帮他处理。除了BSP，很少有一批人会专门找这种简单的Bug来修正。如果没有BSP，debian stable发布的时候一做RC冻结，就要少掉很多有用的包。BSP更大的目的是，交流和传授debian打包和除错的经验，唤起人们的关注。也许在会后，如果有人看到一些简单bug，会使用nmu的方法给与修正。不过BSP到确实是有一个额外加成的好处——基本变成了签名会。昨天估计是中国大陆地区首次DD数量接近其他人数量，我一下弄到了5个签名，2个DD一个Ubuntu员工。加上原来就有的zigo签名，我就有3个DD签名了。</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>本地BSP是在thomas的公司举行，欧特家博士匹萨厂商赞助了我们两天的午餐——微波食品匹萨。第一天来的人比较多，很多都是纯新手，大概有20多人。Zigo倒是在网络上说会帮助新手，但是纯新手看到debian打包系统根本无从下手，所谓指导什么的也无从说起。很多人一天一个bug都修不掉，甚至都看不懂，很有挫折感，估计有不少有热情的人在第二天就这么默默退散了，第二天只来了15个左右。</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>我主要是以修复自己的问题为主，python-snappy和python-formalchemy都升级到了最高级，并且修复了自己以前打包的一个问题。至于RC bug么，我修了一个。两个包在python中命名冲突了，所以在debian中需要声明为conflicts。另外我评审了一下，最终还是决定关闭了python-libmemcached的ITP。虽然对douban很不好意思，还让他们修了一下。但是python-libmemcached依赖于libmemcached，而后者已经逐步升级到了1.0.X版本，但是douban为了稳定使用，是sticky在0.4版上的。因此当更新的debian发行时，实际上python-libmemcached和系统中的libmemcached不是一回事。因此，我不能依赖libmemcached的维护者，而是需要自己去维护后者——没办法，我就是怂了。python-libmemcached的爱用者，还是自己打包吧。我倒是可以公开打包文档。</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>另外，我在想是否要集合一批python/debian的用户，来做投票。例如，python的一个容器——flup，在debian中实际上已经orphon了。如果有足够的人投票，我愿意为flup做接手维护工作。不过目前debian下问下来的结果，大家对flup没什么太大兴趣。</div>
<div></div>
]]></content:encoded>
			<wfw:commentRss>http://shell909090.com/blog/2012/05/%e9%a6%96%e6%ac%a1bsp%e6%97%a5%e8%ae%b0/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>关于昨天”google drive你这是在找死”的补充</title>
		<link>http://shell909090.com/blog/2012/04/%e5%85%b3%e4%ba%8e%e6%98%a8%e5%a4%a9google-drive%e4%bd%a0%e8%bf%99%e6%98%af%e5%9c%a8%e6%89%be%e6%ad%bb%e7%9a%84%e8%a1%a5%e5%85%85/</link>
		<comments>http://shell909090.com/blog/2012/04/%e5%85%b3%e4%ba%8e%e6%98%a8%e5%a4%a9google-drive%e4%bd%a0%e8%bf%99%e6%98%af%e5%9c%a8%e6%89%be%e6%ad%bb%e7%9a%84%e8%a1%a5%e5%85%85/#comments</comments>
		<pubDate>Fri, 27 Apr 2012 23:04:54 +0000</pubDate>
		<dc:creator>shell</dc:creator>
				<category><![CDATA[其他]]></category>

		<guid isPermaLink="false">http://shell909090.com/blog/?p=2156</guid>
		<description><![CDATA[    随手就写害死人阿。 昨天写了一篇google drive你这是在找死，结果被人指出了错。我忘记注明了，没有文件夹上传的是android版本，linux版没有客户端，windows版可以看到客户端下载，但是我目前没有确认下来有人能用。 即使如此，我还是觉得google drive不好用。 # 基于文件的数据管理 # 基于文件的数据管理很简单，一个文件系统有很多目录，每个目录可以放文件或者其他目录，文件里面就是各个程序的数据。基本上每个用电脑的人都知道基于文件的数据管理是怎么回事。 问题是基于文件的数据管理很不好用。 文件就有文件名，我需要找一个文档，里面是上个月的财务数据，但是我不知道叫什么文件名，这种需求并不少见。然而，要在文件系统上干这个事情，你只有搜索所有doc/xls文件，然后一个个看。 蛋疼不蛋疼阿。 基于文件的数据管理的理由，多半因为多文件组合。例如，我有一个html，里面引用了两张图片，一段音乐。在html里面，我只要写明其他文件的文件名，就自然可以指定对其他文件的引用。这省去了“复合数据存储”的烦恼。但是，大部分情况下，我们用不到这个。 因此，目前逐步在向另一个方向过渡，基于数据集合的数据存储。 # 基于数据集合的数据管理 # 数据集合，听起来和文件没什么区别，但是本质上并不是一回事。大家都用过flickr吧，也用过google doc吧。他们基本上就是“基于数据集合的数据管理”。和文件的区别在于，数据集合是有“元数据”的。照片会有拍照时间，说明。如果运气好，还有地点和评论。文档是有作者，简述等等。你可以基于数据类型和元数据进行过滤，排序等动作。而基于文件的基本没有办法这么玩。微软winXP以上版本的资源管理器可以看到，如果文件夹里面多半是图片，就会变成图片专用视图，而显示出图片的内置元数据。然而，这个是逐个扫描的，速度慢。而且万一一个文件夹里面又是图片又是音乐，至少有一个得虾米。 google drive基本是google doc的升级替代品，可以打开多种格式的文件。然而，当上传一个文件时，必须显示的“转换”为google doc文档，才可以介入管理。而且，每个类型的google文档，都有限额。以文本文件为例，大小限制在2M以内。我上传了一个5M的小说，直接报错，要求原样上传。上传后不能直接打开，必须下载打开。 # 整合和过渡 # 两者如何整合？ 在文件系统的管理上，同步，而非上传，是一个非常重要的功能。我不可能每时每刻都联网，即使联网，也不能每个文件修改好了就上传一次。我需要对传统的文件系统做持续的修改，然后通过手工的，或者自动的同步，将差异转移到云端上去。而不是我手工的对比每个文件差异，然后一个一个的上传更新和删除。 没有同步工具的云端存储是个垃圾，除非你共享的目标是少数几个超大的文件，例如电影，或者资源合集之类的东西。这是以共享为目的的云，说的更直白点，就是免费的下载空间，而不是个人云存储。 在个人文件被同步到了云端后，应当能够让云端的程序直接打开和修改某个文件，而不是强迫转换。 # google drive是什么 # 从表现上看，还是基于文件的管理。我不能通过元数据直接查看我拥有多少张相片，也没办法找所有邓丽君的歌。 然而，他们又没有同步，至少linux不行。而且android手机上连文件夹上传都没有。也许有人说了，找个数据线和电脑连起来不就得了？要是我喜欢用数据线连，我到哪连一次电脑，玩个同步就完了，还要云干吗？ 所以，结论还是不变。]]></description>
			<content:encoded><![CDATA[<div>    随手就写害死人阿。</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>昨天写了一篇google drive你这是在找死，结果被人指出了错。我忘记注明了，没有文件夹上传的是android版本，linux版没有客户端，windows版可以看到客户端下载，但是我目前没有确认下来有人能用。</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>即使如此，我还是觉得google drive不好用。</div>
<div></div>
<div># 基于文件的数据管理 #</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>基于文件的数据管理很简单，一个文件系统有很多目录，每个目录可以放文件或者其他目录，文件里面就是各个程序的数据。基本上每个用电脑的人都知道基于文件的数据管理是怎么回事。</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>问题是基于文件的数据管理很不好用。</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>文件就有文件名，我需要找一个文档，里面是上个月的财务数据，但是我不知道叫什么文件名，这种需求并不少见。然而，要在文件系统上干这个事情，你只有搜索所有doc/xls文件，然后一个个看。</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>蛋疼不蛋疼阿。</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>基于文件的数据管理的理由，多半因为多文件组合。例如，我有一个html，里面引用了两张图片，一段音乐。在html里面，我只要写明其他文件的文件名，就自然可以指定对其他文件的引用。这省去了“复合数据存储”的烦恼。但是，大部分情况下，我们用不到这个。</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>因此，目前逐步在向另一个方向过渡，基于数据集合的数据存储。</div>
<div></div>
<div># 基于数据集合的数据管理 #</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>数据集合，听起来和文件没什么区别，但是本质上并不是一回事。大家都用过flickr吧，也用过google doc吧。他们基本上就是“基于数据集合的数据管理”。和文件的区别在于，数据集合是有“元数据”的。照片会有拍照时间，说明。如果运气好，还有地点和评论。文档是有作者，简述等等。你可以基于数据类型和元数据进行过滤，排序等动作。而基于文件的基本没有办法这么玩。微软winXP以上版本的资源管理器可以看到，如果文件夹里面多半是图片，就会变成图片专用视图，而显示出图片的内置元数据。然而，这个是逐个扫描的，速度慢。而且万一一个文件夹里面又是图片又是音乐，至少有一个得虾米。</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>google drive基本是google doc的升级替代品，可以打开多种格式的文件。然而，当上传一个文件时，必须显示的“转换”为google doc文档，才可以介入管理。而且，每个类型的google文档，都有限额。以文本文件为例，大小限制在2M以内。我上传了一个5M的小说，直接报错，要求原样上传。上传后不能直接打开，必须下载打开。</div>
<div></div>
<div># 整合和过渡 #</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>两者如何整合？</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>在文件系统的管理上，同步，而非上传，是一个非常重要的功能。我不可能每时每刻都联网，即使联网，也不能每个文件修改好了就上传一次。我需要对传统的文件系统做持续的修改，然后通过手工的，或者自动的同步，将差异转移到云端上去。而不是我手工的对比每个文件差异，然后一个一个的上传更新和删除。</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>没有同步工具的云端存储是个垃圾，除非你共享的目标是少数几个超大的文件，例如电影，或者资源合集之类的东西。这是以共享为目的的云，说的更直白点，就是免费的下载空间，而不是个人云存储。</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>在个人文件被同步到了云端后，应当能够让云端的程序直接打开和修改某个文件，而不是强迫转换。</div>
<div></div>
<div># google drive是什么 #</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>从表现上看，还是基于文件的管理。我不能通过元数据直接查看我拥有多少张相片，也没办法找所有邓丽君的歌。</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>然而，他们又没有同步，至少linux不行。而且android手机上连文件夹上传都没有。也许有人说了，找个数据线和电脑连起来不就得了？要是我喜欢用数据线连，我到哪连一次电脑，玩个同步就完了，还要云干吗？</div>
<div><span class="Apple-tab-span" style="white-space:pre">	</span>所以，结论还是不变。</div>
<div></div>
]]></content:encoded>
			<wfw:commentRss>http://shell909090.com/blog/2012/04/%e5%85%b3%e4%ba%8e%e6%98%a8%e5%a4%a9google-drive%e4%bd%a0%e8%bf%99%e6%98%af%e5%9c%a8%e6%89%be%e6%ad%bb%e7%9a%84%e8%a1%a5%e5%85%85/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>google drive你这是在找死</title>
		<link>http://shell909090.com/blog/2012/04/google-drive%e4%bd%a0%e8%bf%99%e6%98%af%e5%9c%a8%e6%89%be%e6%ad%bb/</link>
		<comments>http://shell909090.com/blog/2012/04/google-drive%e4%bd%a0%e8%bf%99%e6%98%af%e5%9c%a8%e6%89%be%e6%ad%bb/#comments</comments>
		<pubDate>Thu, 26 Apr 2012 19:36:47 +0000</pubDate>
		<dc:creator>shell</dc:creator>
				<category><![CDATA[其他]]></category>

		<guid isPermaLink="false">http://shell909090.com/blog/?p=2154</guid>
		<description><![CDATA[    昨天收到了google drive的邮件，今天就做了个简单的测试。我不确定是否是我的错觉，但是google drive不支持文件夹上传。     ？！     是的，我找了半天，没找到。即使有这个功能，它也被藏的很深，至少一个熟练用户花了10分钟找不到。据我看到的资料，这是因为谷歌试图抛弃文件概念。     好吧，抛弃文件概念是个先进的理念，我也认为那是对的。但是，当我需要为我的200多个手机小说，一个一个上传，然后再手工建立目录，重新分类，打tag的时候。你连从文件夹直接导入的功能都没有。     告诉我，我为什么要用你。     其余特性我就不多吐槽了，包括中国群众使用的不稳定(虽然不是你们的错，而且dropbox也不稳定)。才5G的免费空间。目前还没有客户端。至少这些问题都是可以改进的(除掉那个不是你们的问题)。     但是拿着已经存在的事实不当回事，只考虑未来是美好的——     ——那就是在找死了。]]></description>
			<content:encoded><![CDATA[<p>    昨天收到了google drive的邮件，今天就做了个简单的测试。我不确定是否是我的错觉，但是google drive不支持文件夹上传。
<div>    ？！</div>
<div>    是的，我找了半天，没找到。即使有这个功能，它也被藏的很深，至少一个熟练用户花了10分钟找不到。据我看到的资料，这是因为谷歌试图抛弃文件概念。</div>
<div>    好吧，抛弃文件概念是个先进的理念，我也认为那是对的。但是，当我需要为我的200多个手机小说，一个一个上传，然后再手工建立目录，重新分类，打tag的时候。你连从文件夹直接导入的功能都没有。</div>
<div>    告诉我，我为什么要用你。</div>
<div>    其余特性我就不多吐槽了，包括中国群众使用的不稳定(虽然不是你们的错，而且dropbox也不稳定)。才5G的免费空间。目前还没有客户端。至少这些问题都是可以改进的(除掉那个不是你们的问题)。</div>
<div>    但是拿着已经存在的事实不当回事，只考虑未来是美好的——</div>
<div>    ——那就是在找死了。</div>
]]></content:encoded>
			<wfw:commentRss>http://shell909090.com/blog/2012/04/google-drive%e4%bd%a0%e8%bf%99%e6%98%af%e5%9c%a8%e6%89%be%e6%ad%bb/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>和谐音程的条件</title>
		<link>http://shell909090.com/blog/2012/04/%e5%92%8c%e8%b0%90%e9%9f%b3%e7%a8%8b%e7%9a%84%e6%9d%a1%e4%bb%b6/</link>
		<comments>http://shell909090.com/blog/2012/04/%e5%92%8c%e8%b0%90%e9%9f%b3%e7%a8%8b%e7%9a%84%e6%9d%a1%e4%bb%b6/#comments</comments>
		<pubDate>Mon, 23 Apr 2012 17:53:01 +0000</pubDate>
		<dc:creator>shell</dc:creator>
				<category><![CDATA[其他]]></category>

		<guid isPermaLink="false">http://shell909090.com/blog/?p=2152</guid>
		<description><![CDATA[    和谐音程的发生条件，是冠音的震动频率和根音呈倍数关系。以此为基础，我们做一个简单计算： 首先是八度： &#62;&#62;&#62; 12*math.log(2, 2) 12.0     即，12个半音(高八度)是和谐音程。 &#62;&#62;&#62; 12*math.log(3.0/2, 2) 7.019550008653875 &#62;&#62;&#62; 12*math.log(4.0/3, 2) 4.980449991346124 &#62;&#62;&#62; 12*math.log(5.0/4, 2) 3.863137138648348 &#62;&#62;&#62; 12*math.log(6.0/5, 2) 3.1564128700055254 &#62;&#62;&#62; 12*math.log(7.0/6, 2) 2.6687090560373763     即，7个半音(纯五度)，5个半音(纯四度)，约4个半音(大三度)，约3个半音(小三度)，为和谐音程。由数值可以看出，纯四纯五的和谐程度又超过大三小三，因为和绝对和谐震动比例的误差更小。     再下面也是可以发生和谐音程的，只是误差更大而已。     为什么是“十二平均率”的原因也很清楚了。 &#8230; <a href="http://shell909090.com/blog/2012/04/%e5%92%8c%e8%b0%90%e9%9f%b3%e7%a8%8b%e7%9a%84%e6%9d%a1%e4%bb%b6/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>    和谐音程的发生条件，是冠音的震动频率和根音呈倍数关系。以此为基础，我们做一个简单计算：
<div>首先是八度：</div>
<div>
<div>&gt;&gt;&gt; 12*math.log(2, 2)</div>
<div>12.0</div>
</div>
<div>    即，12个半音(高八度)是和谐音程。</div>
<div>
<div>&gt;&gt;&gt; 12*math.log(3.0/2, 2)</div>
<div>7.019550008653875</div>
<div>&gt;&gt;&gt; 12*math.log(4.0/3, 2)</div>
<div>4.980449991346124</div>
<div>&gt;&gt;&gt; 12*math.log(5.0/4, 2)</div>
<div>3.863137138648348</div>
</div>
<div>
<div>&gt;&gt;&gt; 12*math.log(6.0/5, 2)</div>
<div>3.1564128700055254</div>
<div>&gt;&gt;&gt; 12*math.log(7.0/6, 2)</div>
<div>2.6687090560373763</div>
</div>
<div>    即，7个半音(纯五度)，5个半音(纯四度)，约4个半音(大三度)，约3个半音(小三度)，为和谐音程。由数值可以看出，纯四纯五的和谐程度又超过大三小三，因为和绝对和谐震动比例的误差更小。</div>
<div>    再下面也是可以发生和谐音程的，只是误差更大而已。</div>
<div>    为什么是“十二平均率”的原因也很清楚了。</div>
<div>
<div>&gt;&gt;&gt; 1/(math.log(3.0/2, 2)-math.log(4.0/3, 2))</div>
<div>5.884949192361715</div>
</div>
<div>    从数值上看，六平均率也是可以的。但是六平均率只能保证第二和三个和谐音程关系在音阶上，要保证第四个，就必须是11平均以上。</div>
<div>
<div>&gt;&gt;&gt; 1/(math.log(4.0/3, 2)-math.log(5.0/4, 2))</div>
<div>10.740053666281327</div>
</div>
<div>    综合两者，12平均率可以基本保证第二三四三个和谐音程都在音阶上。</div>
<div>    同时，也基本满足人类对声音的分辨能力。</div>
]]></content:encoded>
			<wfw:commentRss>http://shell909090.com/blog/2012/04/%e5%92%8c%e8%b0%90%e9%9f%b3%e7%a8%8b%e7%9a%84%e6%9d%a1%e4%bb%b6/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>你认识这人多少？</title>
		<link>http://shell909090.com/blog/2012/04/%e4%bd%a0%e8%ae%a4%e8%af%86%e8%bf%99%e4%ba%ba%e5%a4%9a%e5%b0%91%ef%bc%9f/</link>
		<comments>http://shell909090.com/blog/2012/04/%e4%bd%a0%e8%ae%a4%e8%af%86%e8%bf%99%e4%ba%ba%e5%a4%9a%e5%b0%91%ef%bc%9f/#comments</comments>
		<pubDate>Sun, 22 Apr 2012 18:13:41 +0000</pubDate>
		<dc:creator>shell</dc:creator>
				<category><![CDATA[其他]]></category>

		<guid isPermaLink="false">http://shell909090.com/blog/?p=2150</guid>
		<description><![CDATA[    别误会，这篇是讲个人信息在网络上传播和留存相关话题的。但是不得不说，有点拷问人生的味道。     你究竟认识一个人多少呢？知道名字算认识么？知道性别，年龄，长相，工作单位，算认识么？     这么说吧，如果一个人留了足够多的信息在网络上，你就能找到他/她么？     本周末我就做了这个有趣的研究，事情从欢乐开始，结束于惆怅。 # 我自己认识我自己吧 #     当然，如果不认识自己，您需要做的事情是逆运真气修炼九阴真经，而不是在这里看博客。既然您能够正常阅读博客，我假定您对自己的了解超过对其他任何一个人，同时您也是所有人中最了解自己的。     在这个假定下，贝壳搜索了自己的真名。结果是——第一个？没办法，用真名给网易写过一篇东西，就像在身上绑了一根定位锚一样，看起来很长时间内褪不下去了。Google上大部分都是那篇文章的转载，而baidu上还命中了我的开心首页。好吧，鉴于名人效应，我忽略这篇文章所有有关的内容继续研究。     第二个实验是使用自己的网名，分别搜索baidu和google。结果两者都是全部命中，没有一篇是错误的。可见shell909090是一个罕见关键字，如果你只知道我的英文名shell就糟了，全是某个能源公司和自然生物，翻到10多页都看不到我呢。     第三个实验是联合限定，使用自己的真名加上描述关键词，我首先选用了“程序”。结果是google在第三页找到了两个命中，都是python相关的内容。而baidu翻了三页什么都没有。。。     第四个实验是联合限定，关键词用大学名。结果是baidu三页内什么都没有，google给出了我的一篇论文，还有一篇通知，是我在吉他社当副社长的时候的。如果你知道我弹过吉他，应该能发现那是有关我的信息。     结论： 1. 仅仅搜索我本人而言，baidu只有一次比google强——他上面有开心的信息。后面两次google都给出了比baidu更加准确的关于我的信息。 2. 如果没有网易的这篇文章，很多人不一定找的到我自己。你需要知道我的网名，或者知道我的职业，或者知道就读大学和兴趣。 3. 个人身上的特征比想象的更少，尤其在网络上。我总不能联合我的身高体重吧，长相也没什么用处。一般只有职业，大学，公司这种特征才能有效筛选信息。 4. 你对某人的了解在搜信息的时候多半用不到，在筛选哪条是的时候才用的上。 &#8230; <a href="http://shell909090.com/blog/2012/04/%e4%bd%a0%e8%ae%a4%e8%af%86%e8%bf%99%e4%ba%ba%e5%a4%9a%e5%b0%91%ef%bc%9f/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>    别误会，这篇是讲个人信息在网络上传播和留存相关话题的。但是不得不说，有点拷问人生的味道。
<div>    你究竟认识一个人多少呢？知道名字算认识么？知道性别，年龄，长相，工作单位，算认识么？</div>
<div>    这么说吧，如果一个人留了足够多的信息在网络上，你就能找到他/她么？</div>
<div>    本周末我就做了这个有趣的研究，事情从欢乐开始，结束于惆怅。</div>
<div></div>
<div># 我自己认识我自己吧 #</div>
<div>    当然，如果不认识自己，您需要做的事情是逆运真气修炼九阴真经，而不是在这里看博客。既然您能够正常阅读博客，我假定您对自己的了解超过对其他任何一个人，同时您也是所有人中最了解自己的。</div>
<div>    在这个假定下，贝壳搜索了自己的真名。结果是——第一个？没办法，用真名给网易写过一篇东西，就像在身上绑了一根定位锚一样，看起来很长时间内褪不下去了。Google上大部分都是那篇文章的转载，而baidu上还命中了我的开心首页。好吧，鉴于名人效应，我忽略这篇文章所有有关的内容继续研究。</div>
<div>    第二个实验是使用自己的网名，分别搜索baidu和google。结果两者都是全部命中，没有一篇是错误的。可见shell909090是一个罕见关键字，如果你只知道我的英文名shell就糟了，全是某个能源公司和自然生物，翻到10多页都看不到我呢。</div>
<div>    第三个实验是联合限定，使用自己的真名加上描述关键词，我首先选用了“程序”。结果是google在第三页找到了两个命中，都是python相关的内容。而baidu翻了三页什么都没有。。。</div>
<div>    第四个实验是联合限定，关键词用大学名。结果是baidu三页内什么都没有，google给出了我的一篇论文，还有一篇通知，是我在吉他社当副社长的时候的。如果你知道我弹过吉他，应该能发现那是有关我的信息。</div>
<div>
<p>     结论：</p></div>
<div>1. 仅仅搜索我本人而言，baidu只有一次比google强——他上面有开心的信息。后面两次google都给出了比baidu更加准确的关于我的信息。</div>
<div>2. 如果没有网易的这篇文章，很多人不一定找的到我自己。你需要知道我的网名，或者知道我的职业，或者知道就读大学和兴趣。</div>
<div>3. 个人身上的特征比想象的更少，尤其在网络上。我总不能联合我的身高体重吧，长相也没什么用处。一般只有职业，大学，公司这种特征才能有效筛选信息。</div>
<div>4. 你对某人的了解在搜信息的时候多半用不到，在筛选哪条是的时候才用的上。</div>
<div></div>
<div># 有没有什么别人肯定搜不到的 #</div>
<div>    贝壳其实有一篇IEEE论文，是合作作者。师兄的论文，贝壳提供仿真计算代码，师兄客气，给挂了个名字。这篇论文里，署名是Zhi-Xiang Xu。我自己都是IEEE发通知才知道，别人搜的到才有鬼！</div>
<div></div>
<div>
<p> # 筛我妹看看 #</p></div>
<div>    为什么搜我妹？我基本把人在网络上的信息的多少和类型分为五类。第一类是老太太型，例如我外婆。什么都没有，也不用网络，你搜的到才是怪事。第二类是潜水员型，使用网络，但是不会在网络上使用自己的真名。偶尔帐号丢了就丢了，再申请一个，记得多少朋友就加多少。第三类是网络活跃型，网络上信息很多，但是基本都是网名为基础的，真名信息找不到。第四型是真实人物型，真名信息很多，但是网络上的活动类比一/二型。最后是全面活跃型，主要是网络名人，真名网名都是一堆信息。</div>
<div>    我妹妹是潜水员的典型代表。我跳过整个过程，简述一下结果：满地都是某个书记的言论，无论我用什么关键字搜，基本都找不到相关信息。唯一的命中就是大学里面的考试名单，一个xls文件被公开在了网上。</div>
<div>    结论：</div>
<div>1. 要完全屏蔽信息不是你说了算的，很多时候依赖于学校老师/管理员/公司HR有没有错误的把信息贴出去，尤其是word文档。这是大部分人最容易中枪的地方。</div>
<div>2. 当你的名字或者关键字和某个热关键字重合的时候，你的信息就像被遮盖起来一样，很难从大量垃圾中筛出。</div>
<div>3. baidu基本找不到word文档，估计是没这个能力。</div>
<div></div>
<div># 老婆 #</div>
<div>    本人名字和著名音乐家重合，所以死活找不到。联合大学找不到，联合单位后找到了一篇关于考试的xls文档，确实是她的。</div>
<div>    换网名，我擦，满屏的命中，基本没几个错的，很多我都不知道。。。所以，我慢慢去看了。</div>
<div>    里面还有她的班号，顺着还检索出了她的奖学金。各种信息满坑满谷。网络活跃型典型。</div>
<div></div>
<div># 小学同学 #</div>
<div>    很罕见的名字，输入后直接筛出两篇内容，google和baidu都是同时给出。一篇是该同学写给哈尔滨日报的吐槽，2005年的事情。另一篇是该同学上班后发的文，被收录了。后者有她所属部门的名字，交叉检索后能够多看到一篇文档。影响力不大，估计是内部发行。还有一次去台湾出席会议的经历。资料不是太多，典型的真实人物型啊。</div>
<div></div>
<div> # 以前有过暧昧的女孩子1 #</div>
<div>    恩，别告诉某喵，大家懂。</div>
<div>    跳过过程，上结果：不行，只有她考试的名单。典型的潜水员。</div>
<div></div>
<div>
<div># 某个朋友 #</div>
<div>    出乎贝壳的意料，直接输入姓名后，直接命中开心首页。google还命中了一场官司。从公开的文档中给出的家庭地址来看，确实就是她本人打的官司。这个算是信息的被动泄露，本人还是网络活跃型的吧。</div>
</p></div>
<div></div>
<div># 以前曾经喜欢过的女孩子 #</div>
<div>   曾经听说过此人进了中国一家很有名的网络公司当经理，一搜，果然有。不但有文字材料，还有该公司公关帐号放出的活动照片。近几年基本没怎么大变化，和当初看起来差不多。资料上发的文章，职位变迁一点不少，甚至还有一些帐号。但是没有QQ/开心之类的信息。也就是说，属于真实人物型。</div>
<div>    好吧，看起来不错就好。这么多年，同学之间也只能说看你看起来不错就好。也许再过一段时间，标准会进一步降低为活着就好。</div>
<div></div>
<div># 以前有过暧昧的女孩子2 #</div>
<div>    此人信息非常奇怪。首先是真名什么资料都找不到，那么就是二/三型的。我有她的hotmail，搜索之后找到了一个论坛，上面的资料非常全，而且还找到了一个QQ号。交叉检索QQ号，发现是她当时男朋友的。在德国华人社区有发言，和她说男朋友去德国留学相一致。再检索她的网名，有大量资料。但是奇怪的是，都在某个时间点以前。具体来说，大概是2008年5月前后。之后的信息就完全消失。而她男友的帐号直到今年(2012年)一月还在活跃。结合上述来说，我有种非常不好的预感。更炸头皮的是，我检索了自己和她联系的历史记录。在同一个时间点后，我发送的所有信息都没有回应。包括msn上线状态/聊天记录，手机拜年短信等。。。</div>
<div>    结论：</div>
<div>1. 此人改名搬家，去了德国。配合她男友的记录来看，这种情况不无可能。</div>
<div>2. 此人曾说过，如果要躲某人，就会彻底和自己以前的生活告别，在陌生的城市里过陌生的生活，即使见到也不会相认。我相信她是做的到这点的人。</div>
<div>3. 此人已死。</div>
<div>    好吧，按照最低标准，活着就好。</div>
<div></div>
<div># 总结论 #</div>
<div>1. 现实中大部分人都是一/二型，在网络上什么信息都找不到。之所以没有在贝壳这里体现，是因为贝壳做不到纯随机取样的条件。数据源本身是贝壳自己认识的人，大部分都是受到良好教育，能够熟练使用网络的青年。有不少甚至从事相关行业。用这些人做样本，你可以认为不存在不上网的人。</div>
<div>2. 真的信息上网的人中，大部分都是网络活跃型，即使用网名会命中非常多的信息。上述例子的分析中，贝壳本人/小学同学/之前曾经喜欢过的女孩子在网络上主动留存了本名相关的资料，大约三分之一。但是上面说了，这些例子本身就是网络上留存数据的人的例子。可以粗略的得到结论，大约三分之一上网的人在网络上有真实的个人信息。</div>
<div>3. 根据上条，在网上要找人，用网名比较有效。如果要被人找到，网名不要换比较有效。如果不要被找到，什么真实信息都不留，然后每隔一段时间换个帐号。 </div>
<div>4. 但是一半以上都会被动泄露资料（尤其是xls文件），这说明网络对个人隐私的保护非常差。除去一个公示的例子是必须公开的，其余都是莫名其妙就出现在网上的。即使只通过这些资料还原，大约有三分之一人的基本信息也会被掌握。这本来是没必要的。</div>
]]></content:encoded>
			<wfw:commentRss>http://shell909090.com/blog/2012/04/%e4%bd%a0%e8%ae%a4%e8%af%86%e8%bf%99%e4%ba%ba%e5%a4%9a%e5%b0%91%ef%bc%9f/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>语义的精密表达</title>
		<link>http://shell909090.com/blog/2012/04/%e8%af%ad%e4%b9%89%e7%9a%84%e7%b2%be%e5%af%86%e8%a1%a8%e8%be%be/</link>
		<comments>http://shell909090.com/blog/2012/04/%e8%af%ad%e4%b9%89%e7%9a%84%e7%b2%be%e5%af%86%e8%a1%a8%e8%be%be/#comments</comments>
		<pubDate>Wed, 18 Apr 2012 19:25:34 +0000</pubDate>
		<dc:creator>shell</dc:creator>
				<category><![CDATA[其他]]></category>

		<guid isPermaLink="false">http://shell909090.com/blog/?p=2148</guid>
		<description><![CDATA[    辨析语言的微妙差异，使得语言精密的符合目的语义，此为程序员基本功的最高要求。对精密语义的追求，应当凌驾于排版美观，代码美感，代码简化之上，也凌驾于运行时效率之上。除非为特定目的小幅的修正，否则不应破坏此原则。 以此为指导，我们看几个if。 # if a in python #     以下代码的目标语义是，如果a不为None，就运行代码。 `if a:     do something`     有什么问题？ 有没有考虑a=0的情况？a=[]呢？ `if a is not None:     do something` 这样才是严密表达。 # if a in C #   &#8230; <a href="http://shell909090.com/blog/2012/04/%e8%af%ad%e4%b9%89%e7%9a%84%e7%b2%be%e5%af%86%e8%a1%a8%e8%be%be/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<div>    辨析语言的微妙差异，使得语言精密的符合目的语义，此为程序员基本功的最高要求。对精密语义的追求，应当凌驾于排版美观，代码美感，代码简化之上，也凌驾于运行时效率之上。除非为特定目的小幅的修正，否则不应破坏此原则。</div>
<div><span style="white-space:pre-wrap">	</span>以此为指导，我们看几个if。</div>
<div></div>
<div> # if a in python #</div>
<div>    以下代码的目标语义是，如果a不为None，就运行代码。</div>
<div>`if a:</div>
<div>    do something`</div>
<div>    有什么问题？</div>
<div><span style="white-space:pre-wrap">	</span>有没有考虑a=0的情况？a=[]呢？</div>
<div>`if a is not None:</div>
<div>    do something`</div>
<div><span style="white-space:pre-wrap">	</span>这样才是严密表达。</div>
<div></div>
<div># if a in C #</div>
<div>    以下代码的目标语义是，a是一个int数，对a!=0的情况下，执行代码。</div>
<div>`if (a)</div>
<div>    do something`</div>
<div>    有什么问题？</div>
<div><span style="white-space:pre-wrap">	</span>没问题，因为C是静态语言，这限定了a的使用。除了代码并没有体现a!=0的条件，没有太大问题。但是鉴于语言表达语义，最好改为以下代码。</div>
<div>`if (a != 0)`</div>
<div>    相对的，如果a是bool型，就可以直接用了。</div>
<div>`if (a)`</div>
<div><span style="white-space:pre-wrap">	</span>如果a是char*形，那么合适的语义表达应当是。</div>
<div>`if (a != NULL)`</div>
<div>    他们生成的汇编代码都没有差异。</div>
<div></div>
<div># if a in C++ #</div>
<div>    概念上同C，不过a是一个复杂对象。</div>
<div>`if (a)</div>
<div><span style="white-space:pre-wrap">	</span>do something`</div>
<div><span style="white-space:pre-wrap">	</span>有什么问题？</div>
<div><span style="white-space:pre-wrap">	</span>问题大了去了，和python一样，C++可以重载行为。谁知道type(a)::opreator bool(const type(a) &amp;a)函数被定义为什么鬼逻辑。这就是为什么我憎恨默认行为重载的原因——因为他们对精密语义表达有破坏作用。</div>
<div></div>
]]></content:encoded>
			<wfw:commentRss>http://shell909090.com/blog/2012/04/%e8%af%ad%e4%b9%89%e7%9a%84%e7%b2%be%e5%af%86%e8%a1%a8%e8%be%be/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>值返回和指针返回简说</title>
		<link>http://shell909090.com/blog/2012/04/%e5%80%bc%e8%bf%94%e5%9b%9e%e5%92%8c%e6%8c%87%e9%92%88%e8%bf%94%e5%9b%9e%e7%ae%80%e8%af%b4/</link>
		<comments>http://shell909090.com/blog/2012/04/%e5%80%bc%e8%bf%94%e5%9b%9e%e5%92%8c%e6%8c%87%e9%92%88%e8%bf%94%e5%9b%9e%e7%ae%80%e8%af%b4/#comments</comments>
		<pubDate>Tue, 17 Apr 2012 17:53:48 +0000</pubDate>
		<dc:creator>shell</dc:creator>
				<category><![CDATA[其他]]></category>

		<guid isPermaLink="false">http://shell909090.com/blog/?p=2146</guid>
		<description><![CDATA[    好吧，这是常识，我说快点。     C * c = get_c();     这是指针返回。     C c = get_c():     这是值返回。     指针返回的缺点是，你必须检测返回指针的有效性，也就是NULL。并且，你需要手工管理指针释放。而优点则是避免了值拷贝，还有可以返回空值，即通过返回NULL表示没有值的情况。     而引用返回最大的优势在于，变量的生存周期和作用域相同，你无需管理释放问题。然而缺陷就是庞大的拷贝开销。     在get_c返回的时候，会return一个对象。这个对象是子函数作用域对象(sub function scope)，会随着子函数退出而失效。因此，在返回值的时候会引发拷贝。这种拷贝有两种可能。 1. 拷贝构造     当返回值被用于某个对象的声明时，会触发拷贝构造函数。被返回的对象会作为拷贝构造参数传递(引用传递)，而拷贝出的对象就是被生成对象。 2. 赋值算子 &#8230; <a href="http://shell909090.com/blog/2012/04/%e5%80%bc%e8%bf%94%e5%9b%9e%e5%92%8c%e6%8c%87%e9%92%88%e8%bf%94%e5%9b%9e%e7%ae%80%e8%af%b4/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>    好吧，这是常识，我说快点。
<div>    C * c = get_c();</div>
<div>    这是指针返回。</div>
<div>    C c = get_c():</div>
<div>    这是值返回。</div>
<div></div>
<div>    指针返回的缺点是，你必须检测返回指针的有效性，也就是NULL。并且，你需要手工管理指针释放。而优点则是避免了值拷贝，还有可以返回空值，即通过返回NULL表示没有值的情况。</div>
<div>
<p>     而引用返回最大的优势在于，变量的生存周期和作用域相同，你无需管理释放问题。然而缺陷就是庞大的拷贝开销。</p></div>
<div>    在get_c返回的时候，会return一个对象。这个对象是子函数作用域对象(sub function scope)，会随着子函数退出而失效。因此，在返回值的时候会引发拷贝。这种拷贝有两种可能。</div>
<div>1. 拷贝构造</div>
<div>    当返回值被用于某个对象的声明时，会触发拷贝构造函数。被返回的对象会作为拷贝构造参数传递(引用传递)，而拷贝出的对象就是被生成对象。</div>
<div>2. 赋值算子</div>
<div>    即operator =。当对某个已经声明对象进行赋值时，会发生这种现象。</div>
<div>    当然，近代编译器对于“在返回时进行构造用于返回后的构造”这种情况做了优化，通称RVO优化。例如上文，如果get_c中使用return C(a, b);进行返回，实际上只有C::C(a, b)的调用，而没有C::C(const C &amp; c)的调用。</div>
]]></content:encoded>
			<wfw:commentRss>http://shell909090.com/blog/2012/04/%e5%80%bc%e8%bf%94%e5%9b%9e%e5%92%8c%e6%8c%87%e9%92%88%e8%bf%94%e5%9b%9e%e7%ae%80%e8%af%b4/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>vps上应当装什么</title>
		<link>http://shell909090.com/blog/2012/04/vps%e4%b8%8a%e5%ba%94%e5%bd%93%e8%a3%85%e4%bb%80%e4%b9%88/</link>
		<comments>http://shell909090.com/blog/2012/04/vps%e4%b8%8a%e5%ba%94%e5%bd%93%e8%a3%85%e4%bb%80%e4%b9%88/#comments</comments>
		<pubDate>Mon, 16 Apr 2012 23:00:21 +0000</pubDate>
		<dc:creator>shell</dc:creator>
				<category><![CDATA[其他]]></category>

		<guid isPermaLink="false">http://shell909090.com/blog/?p=2144</guid>
		<description><![CDATA[    假定你有一台debian vps，上面需要装一些东西来——你懂。你应该装一些什么呢？ # 基础部分 # ## ssh ## 没啥好多说，没有ssh，你甚至无法管理机器。不过注意，安全的ssh方式应当只允许使用key登录，禁止一切密码登录。而且对于没必要登录的某些用户，需要在/etc/passwd中将shell改为/bin/false。至于端口改不改，这个不重要，看你心情。 ## vim ## debian默认装的是vim-tiny，很不好用。建议改为vim，改配置的时候让自己舒服点。 ## 安全部分 ## ## iptables-persistent ## 这是debian内用于iptables规则持久化的工具，你可以编辑/etc/iptables/rules.v4来修改防火墙规则。注意，目前debian stable(squeeze)中的版本还没有4/6区分，你可以弄一个testing(wheezy)中的来装。 一般来说，你的规则中至少要包含以下内容： ` -A INPUT -m state &#8211;state RELATED,ESTABLISHED -j ACCEPT -A INPUT -i lo -j ACCEPT -A &#8230; <a href="http://shell909090.com/blog/2012/04/vps%e4%b8%8a%e5%ba%94%e5%bd%93%e8%a3%85%e4%bb%80%e4%b9%88/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<div>
<div>    假定你有一台debian vps，上面需要装一些东西来——你懂。你应该装一些什么呢？</div>
<div></div>
<div># 基础部分 #</div>
<div>## ssh ##</div>
<div><span style="white-space:pre-wrap">	</span>没啥好多说，没有ssh，你甚至无法管理机器。不过注意，安全的ssh方式应当只允许使用key登录，禁止一切密码登录。而且对于没必要登录的某些用户，需要在/etc/passwd中将shell改为/bin/false。至于端口改不改，这个不重要，看你心情。</div>
<div>## vim ##</div>
<div><span style="white-space:pre-wrap">	</span>debian默认装的是vim-tiny，很不好用。建议改为vim，改配置的时候让自己舒服点。</div>
<div></div>
<div>## 安全部分 ##</div>
<div>## iptables-persistent ##</div>
<div><span style="white-space:pre-wrap">	</span>这是debian内用于iptables规则持久化的工具，你可以编辑/etc/iptables/rules.v4来修改防火墙规则。注意，目前debian stable(squeeze)中的版本还没有4/6区分，你可以弄一个testing(wheezy)中的来装。</div>
<div><span style="white-space:pre-wrap">	</span>一般来说，你的规则中至少要包含以下内容：</div>
<div>`</div>
<div>-A INPUT -m state &#8211;state RELATED,ESTABLISHED -j ACCEPT</div>
<div>-A INPUT -i lo -j ACCEPT</div>
<div>-A INPUT -i tun+ -j ACCEPT</div>
<div>-A INPUT -i ppp+ -j ACCEPT</div>
<div>-A INPUT -p tcp -m multiport &#8211;dport 22,xxx,xxx,xxx -j ACCEPT</div>
<div>-A INPUT -p udp -m multiport &#8211;dport xxx,xxx,xxx -j ACCEPT</div>
<div>`</div>
<div><span style="white-space:pre-wrap">	</span>而且强烈建议，先保存一个没问题的iptables，然后直接修改iptables，再保存。这样的好处是，当你脑残改错了导致你自己都无法管理的时候，只要重启就可以恢复vps工作，而不用更麻烦的动作。</div>
<div>## denyhosts ##</div>
<div><span style="white-space:pre-wrap">	</span>这是ssh的连接防御进程，用python编写。如果有人试图尝试你的ssh密码，这个程序就会踢掉他的ip。</div>
<div><span style="white-space:pre-wrap">	</span>如果你已经用了我说的，通过key的连接方式，你可以一次就直接踢掉对方ip。</div>
<div></div>
<div># 管理部分 #</div>
<div>## ifstat ##</div>
<div><span style="white-space:pre-wrap">	</span>ifstat是用于网络流量管理的工具，可以告诉你网络目标的流量是多少。</div>
<div>## dnsutils ##</div>
<div><span style="white-space:pre-wrap">	</span>dnsutils里面包含了不少用于管理dns的工具，包括我们常用的nslookup，还有相对少用的dig。</div>
<div>## mtr-tiny ##</div>
<div><span style="white-space:pre-wrap">	</span>mtr是一个traceroute工具，比后者好用很多。这个工具可以快速跟踪路由。</div>
<div>## vnstat ##</div>
<div><span style="white-space:pre-wrap">	</span>vnstat是用于跟踪网卡流量的工具，尤其对于每个月都有限额的vps，这个工具更有意义。</div>
<div><span style="white-space:pre-wrap">	</span>注意安装完成后需要初始化每个网卡，然后重启服务，而不是马上能够工作。</div>
<div></div>
<div># 网络部分 #</div>
<div>## pptp ##</div>
<div><span style="white-space:pre-wrap">	</span>pptp是一个经典的vpn服务，直接安装pptpd就好。注意，部分手机不支持128bit的mppe，关闭后可以连接。但是windows只支持128bit的mppe，关掉就无法连接。So，自己权衡。</div>
<div>## openvpn ##</div>
<div><span style="white-space:pre-wrap">	</span>openpn是一个非常稳定而强大的vpn程序，他使用udp作为连接协议。其实openvpn有tcp协议模式，但是速度比udp慢很多。</div>
<div><span style="white-space:pre-wrap">	</span>openvpn的配置很长，我也写过，就不赘述了，可以参考这三篇文章([1.搭建家用的OpenVPN服务器](<a href="http://shell909090.com/blog/2009/09/%E6%90%AD%E5%BB%BA%E5%AE%B6%E7%94%A8%E7%9A%84openvpn%E6%9C%8D%E5%8A%A1%E5%99%A8/" target="_blank">http://shell909090.com/blog/2009/09/%E6%90%AD%E5%BB%BA%E5%AE%B6%E7%94%A8%E7%9A%84openvpn%E6%9C%8D%E5%8A%A1%E5%99%A8/</a>), [2.说说x509证书链](<a href="http://shell909090.com/blog/2011/04/%E8%AF%B4%E8%AF%B4x509%E8%AF%81%E4%B9%A6%E9%93%BE/" target="_blank">http://shell909090.com/blog/2011/04/%E8%AF%B4%E8%AF%B4x509%E8%AF%81%E4%B9%A6%E9%93%BE/</a>), [3.再论openvpn的搭建](<a href="http://shell909090.com/blog/2011/05/%E5%86%8D%E8%AE%BAopenvpn%E7%9A%84%E6%90%AD%E5%BB%BA/)" target="_blank">http://shell909090.com/blog/2011/05/%E5%86%8D%E8%AE%BAopenvpn%E7%9A%84%E6%90%AD%E5%BB%BA/)</a>)。</div>
<div>## l2tp ##</div>
<div><span style="white-space:pre-wrap">	</span>l2tp的配置比openvpn更加繁琐，我配置过多次，始终在部分的设备上可以访问，部分不可以。因此等全部搞定后，会专门写一篇确认一下。</div>
<div>## iodine ##</div>
<div><span style="white-space:pre-wrap">	</span>iodine是一个dns vpn。</div>
<div>## ssh ##</div>
<div><span style="white-space:pre-wrap">	</span>ssh用于翻墙常见两种模式，固定端口转发和动态端口转发。前者使用-R将远程的某个端口映射到本地。通常而言，映射的都是squid或者polipo(推荐后者，内存消耗更小，更好配置)。这样相当于在本地可以访问远程的代理，从而达到翻墙的效果。这个的命令行是ssh -L port:localhost:port &#8230;</div>
<div><span style="white-space:pre-wrap">	</span>而动态端口转发则是使用ssh -D port &#8230;，将本地的port端口变成一个支持socks5协议的代理服务器。</div>
<div><span style="white-space:pre-wrap">	</span>相比而言，-D模式更加灵活，提供了全协议的访问，本地可以通过polipo转换为http代理。而-L模式则不能提供socks5代理功能(除非远程的端口上是socks5代理服务，但是这样就回到了-D模式，反而多开了一个服务)。但是有些时候(例如android的ssh翻墙软件)只支持后者的模式。</div>
<div><span style="white-space:pre-wrap">	</span>另外，不要用日常管理帐号翻墙。新开一个翻墙帐号，并且设定独立的key。然后禁用shell，在ssh的时候，使用参数-CNq，这个参数可以不打开shell。如果网络不稳定，可以加上-o ServerAliveInterval 30。</div>
<div>## stunnel ##</div>
<div><span style="white-space:pre-wrap">	</span>stunnel本身没有任何功效，他只是将你的普通连接转换为ssl连接而已。当这个程序搭配其他程序，例如polipo，就可以实现一个ssl级别的代理。</div>
<div>## httptunnel ##</div>
<div><span style="white-space:pre-wrap">	</span>这是一个服务软件，服务器端运行一个httptunnel，客户端运行一个。而后客户端就可以获得一个到服务器端的tcp连接，不受限的。</div>
<div>## polipo ##</div>
<div><span style="white-space:pre-wrap">	</span>polipo常见有两种模式，端口转发模式和ssl模式。两者都在前文有说。端口转发模式配合ssh用，ssl模式配合stunnel用。</div>
<div></div>
<div><span style="white-space:pre-wrap">	</span>以上的服务看似很多，实际上，在128M内存的实例上完全可以运行其中大部分的服务。你可以在一台服务器上运行其中多个，以保证全天候的服务。</div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://shell909090.com/blog/2012/04/vps%e4%b8%8a%e5%ba%94%e5%bd%93%e8%a3%85%e4%bb%80%e4%b9%88/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>2012年4月12日断网的技术记录</title>
		<link>http://shell909090.com/blog/2012/04/2012%e5%b9%b44%e6%9c%8812%e6%97%a5%e6%96%ad%e7%bd%91%e7%9a%84%e6%8a%80%e6%9c%af%e8%ae%b0%e5%bd%95/</link>
		<comments>http://shell909090.com/blog/2012/04/2012%e5%b9%b44%e6%9c%8812%e6%97%a5%e6%96%ad%e7%bd%91%e7%9a%84%e6%8a%80%e6%9c%af%e8%ae%b0%e5%bd%95/#comments</comments>
		<pubDate>Sun, 15 Apr 2012 18:24:40 +0000</pubDate>
		<dc:creator>shell</dc:creator>
				<category><![CDATA[其他]]></category>

		<guid isPermaLink="false">http://shell909090.com/blog/?p=2142</guid>
		<description><![CDATA[    4月12日上午, 大约北京时间10点(UTC02:00前后), 中国大部分地区发生了一次断网. 这次断网我有幸正好在使用网络, 因此跟踪调试了整个过程. 1. 网络开始中断    当时我在公司里面用ssh调整一台国外的机器, 同时用另一台机器作为ssh跳板访问google. 问题发生的时候, 很多国外网站都无法打开, ssh指令不能工作. 我的第一反应就是, GFW针对ssh做了拦截.    鉴于其他可能, 我登录回了家中, 从家里的机器直接ssh到国外的跳板, 一切正常. 莫非只是我这里的ssh发生了断路? 我正在这么猜测的时候, 家里的ssh也随即断开. 我kill了当前进程, 重新连接后, 恢复了对家里服务器的控制, 但是境外的ssh跳板已经不能连接.    至此, 可以确定中国出国网络逐步发生中断, 针对什么协议, 机制如何尚不清楚.    但是, 我同时用同一台机器打开了openvpn, openvpn会提供一个内网接口. 我偶然的用这个内网iface访问了一下, 一切正常. &#8230; <a href="http://shell909090.com/blog/2012/04/2012%e5%b9%b44%e6%9c%8812%e6%97%a5%e6%96%ad%e7%bd%91%e7%9a%84%e6%8a%80%e6%9c%af%e8%ae%b0%e5%bd%95/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<div>    4月12日上午, 大约北京时间10点(UTC02:00前后), 中国大部分地区发生了一次断网. 这次断网我有幸正好在使用网络, 因此跟踪调试了整个过程.</div>
<div></div>
<div>1. 网络开始中断</div>
<div>   当时我在公司里面用ssh调整一台国外的机器, 同时用另一台机器作为ssh跳板访问google. 问题发生的时候, 很多国外网站都无法打开, ssh指令不能工作. 我的第一反应就是, GFW针对ssh做了拦截.</div>
<div>   鉴于其他可能, 我登录回了家中, 从家里的机器直接ssh到国外的跳板, 一切正常. 莫非只是我这里的ssh发生了断路? 我正在这么猜测的时候, 家里的ssh也随即断开. 我kill了当前进程, 重新连接后, 恢复了对家里服务器的控制, 但是境外的ssh跳板已经不能连接.</div>
<div>   至此, 可以确定中国出国网络逐步发生中断, 针对什么协议, 机制如何尚不清楚.</div>
<div>   但是, 我同时用同一台机器打开了openvpn, openvpn会提供一个内网接口. 我偶然的用这个内网iface访问了一下, 一切正常. 再尝试了一下, openvpn上网正常. 这说明问题可能局限在ssh上.</div>
<div></div>
<div>2. 这不是一个个例, 这是大规模断网</div>
<div>   既然我对境外服务器还有控制能力, 我就更换了一个ssh端口, 但是问题并没有解决. 这似乎说明封锁不是针对端口(port), 而是针对协议(protocol)的. 为了确证这点, 我对通讯过程做了抓包, 但是结果出乎我的意料. 问题并不出现在ssh握手的时候, 而是tcp第二步的syn-ack回包彻底消失. 这表明封锁并不针对ssh协议, 而是tcp协议栈!</div>
<div>   这非常疯狂, 如果是这样的话, 大部分基于tcp的网络协议将无法工作, 包括境外大部分网站的http协议. 我从twitter上看到, 很多人的各种工具都相继失效, 并且境外很多的http(而非https)确实无法访问, 这和我的判断相一致. 这是针对tcp协议栈的大规模拦截.</div>
<div></div>
<div>3. 为什么特殊</div>
<div>   通常而言, GFW有三个常见工作模式.</div>
<div> * dns污染</div>
<div>* ip封锁</div>
<div>* 深度包过滤(关键字拦截)</div>
<div>  其中dns封锁只对域名有效, ip封锁只对ip有效, 只有深度包过滤才是最麻烦的. 但是通常深度包过滤是使用旁路过滤的方式, 在连接出现问题时发出rst包干扰tcp工作. 而本次的模式是将境外向境内的tcp包直接丢弃, 而非rst. 这是ip封锁的模式. 根据上文的经验和我在twitter上收集的有限几个数据, 封锁范围似乎随着不同的网络连接方式而发生变化. 我这里可以连接的设备在其他人那里就无法继续连接, 反之亦然. 似乎是在多个不同的核心路由器上逐步部署不同的路由器规则, 对境外的特定回包给与丢弃. 这表示GFW的工作模式有可能从包检测向白名单过渡.</div>
<div></div>
<div>4. 为什么麻烦</div>
<div>   白名单是很难对付的一种模式. 对于深度包检测, 可以通过修改包的封装性质予以绕过. ssh/vpn都是这类的典型方式. 然而白名单使得你很难在境外部署一台处于你自己控制之下的服务器. 即使你可以在境外弄到一台服务器(这到不困难), 也没有希望将服务器ip加入白名单内. 由于白名单内的都是国家认可的服务器, 因此上面运作的服务基本都是无可能进行绕行的.</div>
]]></content:encoded>
			<wfw:commentRss>http://shell909090.com/blog/2012/04/2012%e5%b9%b44%e6%9c%8812%e6%97%a5%e6%96%ad%e7%bd%91%e7%9a%84%e6%8a%80%e6%9c%af%e8%ae%b0%e5%bd%95/feed/</wfw:commentRss>
		<slash:comments>23</slash:comments>
		</item>
		<item>
		<title>mirrors.geekbone.org软件仓库镜像站将于4月中旬下线</title>
		<link>http://shell909090.com/blog/2012/04/mirrors-geekbone-org%e8%bd%af%e4%bb%b6%e4%bb%93%e5%ba%93%e9%95%9c%e5%83%8f%e7%ab%99%e5%b0%86%e4%ba%8e4%e6%9c%88%e4%b8%ad%e6%97%ac%e4%b8%8b%e7%ba%bf/</link>
		<comments>http://shell909090.com/blog/2012/04/mirrors-geekbone-org%e8%bd%af%e4%bb%b6%e4%bb%93%e5%ba%93%e9%95%9c%e5%83%8f%e7%ab%99%e5%b0%86%e4%ba%8e4%e6%9c%88%e4%b8%ad%e6%97%ac%e4%b8%8b%e7%ba%bf/#comments</comments>
		<pubDate>Thu, 12 Apr 2012 17:38:56 +0000</pubDate>
		<dc:creator>shell</dc:creator>
				<category><![CDATA[其他]]></category>

		<guid isPermaLink="false">http://shell909090.com/blog/?p=2140</guid>
		<description><![CDATA[    原文[在此](http://www.shlug.org/?p=1515)。我用了5年多的cn99和geekbone两大镜像终于全部下线。     需要通告的一点关键问题即是, 由于tux下线早于新一个版本的debian发行, 因此目前mirrors.geekbone.org还是已经发行的debian安装盘的官方源之一. 请大家在安装debian6的时候不要再选择geekbone, 并请通告其他debian用户.     在09年加入shlug之初，就知道当年用了很久的geekbone服务器是shlug管理维护的。当时就很惊讶，以捐助方式运作一台镜像服务器，这个是相当不容易的。包括募集，管理，账目，在中国要做整套过程需要相当心力。而且geekbone还是在debian有注册的镜像站之一。可以看[Debian 全球鏡像站](http://www.debian.org/mirror/list)。     大约在11年，中科大的ustc服务器上线后。在一次和lightning的闲聊中，lightning就谈到了tux服务器的问题。当时tux的服务器硬盘已经不足，最多在数月后就会满额。lightning删除了部分上面的无用数据，让服务器可以稍稍多工作一些时日。我当时就建议不要全面镜像所有的debian镜像，毕竟当时中国已经有anheng和ustc两个全面源，其中ustc还在申请大陆一级源(他们的资源投入确实不错，镜像速度相当快)。tux毕竟是老服务器，可以转做i386和amd64两个主要镜像。国内大部分人用的都是这两个arch，sohu的部分镜像也是针对这部分的。lightning表示看看再说。     今天，看到了shlug通告，tux服务器准备下线。想想也的却是，tux已经在超期服役，而国内已经有了ustc, anheng, sohu, bjtu四个镜像. 再进行一次募捐让tux恢复服役看来是没什么必要了.     在此, 感谢一下shlug服务器维护团队, 谢谢你们的努力让我五年来得以享用快速的源服务. 祝tux一路走好, 愿电脑诸神与它同在, enter.     另外, 提一点我们和欧美的工业水准差距. 我曾经撰文说过, 中国要追赶美国还有很长的路要走. 当时列举的证据就是dd和debian mirror &#8230; <a href="http://shell909090.com/blog/2012/04/mirrors-geekbone-org%e8%bd%af%e4%bb%b6%e4%bb%93%e5%ba%93%e9%95%9c%e5%83%8f%e7%ab%99%e5%b0%86%e4%ba%8e4%e6%9c%88%e4%b8%ad%e6%97%ac%e4%b8%8b%e7%ba%bf/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<div>    原文[在此](<a href="http://www.shlug.org/?p=1515)%E3%80%82" target="_blank">http://www.shlug.org/?p=1515)。</a>我用了5年多的cn99和geekbone两大镜像终于全部下线。</div>
<div>    需要通告的一点关键问题即是, 由于tux下线早于新一个版本的debian发行, 因此目前<a href="http://mirrors.geekbone.org">mirrors.geekbone.org</a>还是已经发行的debian安装盘的官方源之一. 请大家在安装debian6的时候不要再选择geekbone, 并请通告其他debian用户.</div>
<div>    在09年加入shlug之初，就知道当年用了很久的geekbone服务器是shlug管理维护的。当时就很惊讶，以捐助方式运作一台镜像服务器，这个是相当不容易的。包括募集，管理，账目，在中国要做整套过程需要相当心力。而且geekbone还是在debian有注册的镜像站之一。可以看[Debian 全球鏡像站](<a href="http://www.debian.org/mirror/list" target="_blank">http://www.debian.org/mirror/list</a>)。</div>
<div>    大约在11年，中科大的ustc服务器上线后。在一次和lightning的闲聊中，lightning就谈到了tux服务器的问题。当时tux的服务器硬盘已经不足，最多在数月后就会满额。lightning删除了部分上面的无用数据，让服务器可以稍稍多工作一些时日。我当时就建议不要全面镜像所有的debian镜像，毕竟当时中国已经有anheng和ustc两个全面源，其中ustc还在申请大陆一级源(他们的资源投入确实不错，镜像速度相当快)。tux毕竟是老服务器，可以转做i386和amd64两个主要镜像。国内大部分人用的都是这两个arch，sohu的部分镜像也是针对这部分的。lightning表示看看再说。</div>
<div>    今天，看到了shlug通告，tux服务器准备下线。想想也的却是，tux已经在超期服役，而国内已经有了ustc, anheng, sohu, bjtu四个镜像. 再进行一次募捐让tux恢复服役看来是没什么必要了.</div>
<div>    在此, 感谢一下shlug服务器维护团队, 谢谢你们的努力让我五年来得以享用快速的源服务. 祝tux一路走好, 愿电脑诸神与它同在, enter.</div>
<div>    另外, 提一点我们和欧美的工业水准差距. 我曾经撰文说过, 中国要追赶美国还有很长的路要走. 当时列举的证据就是dd和debian mirror lists. 当时我们也是4个源, 目前加入了bjtu, tux退出, 还是4个源. 相比美国那个深不见底, 鼠标滚轮滚好几下都没看到头的列表, 实在是太差距了. 这个差距不仅体现在源少, 更体现在用户少. 用户少就是源少的原因. 如果用户增长一个数量级, 目前这些源肯定会发生不足, 然后吵着让各个大学再开一两个镜像出来. 我倒是觉得这样不错, 至少sjtu有机会露个脸. 其实sjtu也是有自己的[源](<a href="http://ftp.sjtu.edu.cn/debian/)%E7%9A%84" target="_blank">http://ftp.sjtu.edu.cn/debian/)的</a>, 只是没有对普通网络用户开放, 访问速度缓慢而已.</div>
]]></content:encoded>
			<wfw:commentRss>http://shell909090.com/blog/2012/04/mirrors-geekbone-org%e8%bd%af%e4%bb%b6%e4%bb%93%e5%ba%93%e9%95%9c%e5%83%8f%e7%ab%99%e5%b0%86%e4%ba%8e4%e6%9c%88%e4%b8%ad%e6%97%ac%e4%b8%8b%e7%ba%bf/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>segment的核心数据结构空间和时间效率估量</title>
		<link>http://shell909090.com/blog/2012/04/segment%e7%9a%84%e6%a0%b8%e5%bf%83%e6%95%b0%e6%8d%ae%e7%bb%93%e6%9e%84%e7%a9%ba%e9%97%b4%e5%92%8c%e6%97%b6%e9%97%b4%e6%95%88%e7%8e%87%e4%bc%b0%e9%87%8f/</link>
		<comments>http://shell909090.com/blog/2012/04/segment%e7%9a%84%e6%a0%b8%e5%bf%83%e6%95%b0%e6%8d%ae%e7%bb%93%e6%9e%84%e7%a9%ba%e9%97%b4%e5%92%8c%e6%97%b6%e9%97%b4%e6%95%88%e7%8e%87%e4%bc%b0%e9%87%8f/#comments</comments>
		<pubDate>Wed, 11 Apr 2012 17:55:37 +0000</pubDate>
		<dc:creator>shell</dc:creator>
				<category><![CDATA[其他]]></category>

		<guid isPermaLink="false">http://shell909090.com/blog/?p=2138</guid>
		<description><![CDATA[    首先我们简述核心词典的目标。词典最主要的目标是，给定一句句子S，匹配出所有和句子开始拥有完整匹配的词语。所谓完整匹配，就是句子开始的一定长度的连续序列和词语相等。例如，中华，中华人民，中华人民共和国，都是句子：中华人民共和国今天成立了，的完整匹配。     要解决这个问题，直观方式是使用tied tree。但是中文的tied tree非常不好实现。英文的tied tree在一个节点上最多拥有不超过26个子节点，而中文的在根上面会拥有6000个以上的子节点，使用同样的结构在子节点上会浪费大量内存。     我们先跳过tied树本身的细节，来讨论如何使用python内置数据结构高效简洁的完成这一工作。作为一个读比写高频很多的结构，无疑hash table是一个非常适合的结构。我在hash table的性能分析中说过，hash table的查询性能是O(1)量级的。无疑，可以使用hash tree来高速完成查找。同时注意一点，词语的最小长度是2，因此不存在只有一级的结构。所以，hash tree的第一级结构可以从2开始，而不是1。     实现效果如何？我们正式给出的词典拥有127K的词汇量，平均第二级宽度为6.8，因此大致可以推算出，第一级的词典含有元素19K个左右。python源码解析中说过，当表项小于50000个时，扩张大小为当前活跃表项的4倍，最高填充率不超过2/3，即填充率最低25%，最高66%。平均来说，填充率应当在45%上下波动，我们以0.5计算，实际上一级词典的Entry个数应当是40K个上下。在源码Include/dictobject.h:50有给出Entry的结构，这应当是三个平台相关的数据结构，以贝壳的64位系统而言，长度应当是24字节。忽略掉辅助结构，一级词典的大小应当是960K，即约1M。而词典指向的数据，即2字长的str对象本身头部长度24字节，辅助数据长度12字节，数据长度4字节（utf-16编码的两个unicode），null term1字节，共计41字节。由于python对象是8字节对齐，因此实际占用48字节。19K个数据总计占用912K。     二级表项平均长度6.8，这个长度很难估量。因为5的话总表项刚好是8，而6就会增长到24，我们取中间数20做一个估量值（因为6.8毕竟大大偏离了5），一个词典的大小应当是480字节，加上头部大约是512字节（算的粗糙点吧），19K个词典就是8.5M左右。指向的对象长度更加难估量，我们粗糙点按照96字节一个对象（别忘记了，unicode对象不但成员多，而且超出了BOM，一个字占4字节），127K个对象大约是12M内存。而float内部使用C的double类型，一个对象占据32字节，127K个对象占据4M内存。     以上总计，初级词典本身占用1M，关键字占1M。二级索引占据10M，关键字占12M，频率数据占4M。总计28M内存，基本上一个12.7W词的词典，大小2.5M，占据30M内存，这就是dict核心词典的空间效率估量。     时间复杂度估量更加复杂，不过我们可以简化来说。初级索引需要多少时间？O(1)量级，毋庸置疑。问题是二级词典的复杂度，异常难算。凑合一下，按照比较6.8次计算（因为必须通过遍历才能知道全部的匹配）索引出一个句子所有的完整匹配的时间复杂度O应当为O(n)，其中n是平均二级索引宽度。目前而言，实际测量结果，平均6.8。当词汇量大于一定值后，随着词典的加大，这个值基本是线性增加的，我们粗略的可以认为O(n)即是正比于词典大小。     而后我们顺便给出分词核心算法在处理一句话时的效率估量吧，证明太长，这里写不下。假定句子长度S，词典大小N，匹配数目M，分词算法的时间复杂度量级为O(N*M*S)，有兴趣的可以帮我复核一下，这个证明颇为困难，不知道有没有证错。在实际运行的时候，匹配数目会跟着词典的增长而增长，而句子长度则相对固定。当然，明眼人一眼就可以看出，所谓匹配数据随着词典增长而增长，其中并不是正比的。而是O(1)&#60;O&#60;O(n)。因此我们可以看作时间复杂度为O(N)&#60;O&#60;O(N^2)，具体是什么，做不出来。     然后是纯粹的tied tree的性能估量。讲到tied tree，我们就必须要提到如何实现一个有效的tied tree。实际上纯粹用区域哈希映射太浪费内存了，而顺序查找太浪费时间。比较折衷的办法还是只有——dynamic hash &#8230; <a href="http://shell909090.com/blog/2012/04/segment%e7%9a%84%e6%a0%b8%e5%bf%83%e6%95%b0%e6%8d%ae%e7%bb%93%e6%9e%84%e7%a9%ba%e9%97%b4%e5%92%8c%e6%97%b6%e9%97%b4%e6%95%88%e7%8e%87%e4%bc%b0%e9%87%8f/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<div>    首先我们简述核心词典的目标。词典最主要的目标是，给定一句句子S，匹配出所有和句子开始拥有完整匹配的词语。所谓完整匹配，就是句子开始的一定长度的连续序列和词语相等。例如，中华，中华人民，中华人民共和国，都是句子：中华人民共和国今天成立了，的完整匹配。</div>
<div>    要解决这个问题，直观方式是使用tied tree。但是中文的tied tree非常不好实现。英文的tied tree在一个节点上最多拥有不超过26个子节点，而中文的在根上面会拥有6000个以上的子节点，使用同样的结构在子节点上会浪费大量内存。</div>
<div>    我们先跳过tied树本身的细节，来讨论如何使用python内置数据结构高效简洁的完成这一工作。作为一个读比写高频很多的结构，无疑hash table是一个非常适合的结构。我在hash table的性能分析中说过，hash table的查询性能是O(1)量级的。无疑，可以使用hash tree来高速完成查找。同时注意一点，词语的最小长度是2，因此不存在只有一级的结构。所以，hash tree的第一级结构可以从2开始，而不是1。</div>
<div>    实现效果如何？我们正式给出的词典拥有127K的词汇量，平均第二级宽度为6.8，因此大致可以推算出，第一级的词典含有元素19K个左右。python源码解析中说过，当表项小于50000个时，扩张大小为当前活跃表项的4倍，最高填充率不超过2/3，即填充率最低25%，最高66%。平均来说，填充率应当在45%上下波动，我们以0.5计算，实际上一级词典的Entry个数应当是40K个上下。在源码Include/dictobject.h:50有给出Entry的结构，这应当是三个平台相关的数据结构，以贝壳的64位系统而言，长度应当是24字节。忽略掉辅助结构，一级词典的大小应当是960K，即约1M。而词典指向的数据，即2字长的str对象本身头部长度24字节，辅助数据长度12字节，数据长度4字节（utf-16编码的两个unicode），null term1字节，共计41字节。由于python对象是8字节对齐，因此实际占用48字节。19K个数据总计占用912K。</div>
<div>    二级表项平均长度6.8，这个长度很难估量。因为5的话总表项刚好是8，而6就会增长到24，我们取中间数20做一个估量值（因为6.8毕竟大大偏离了5），一个词典的大小应当是480字节，加上头部大约是512字节（算的粗糙点吧），19K个词典就是8.5M左右。指向的对象长度更加难估量，我们粗糙点按照96字节一个对象（别忘记了，unicode对象不但成员多，而且超出了BOM，一个字占4字节），127K个对象大约是12M内存。而float内部使用C的double类型，一个对象占据32字节，127K个对象占据4M内存。</div>
<div>    以上总计，初级词典本身占用1M，关键字占1M。二级索引占据10M，关键字占12M，频率数据占4M。总计28M内存，基本上一个12.7W词的词典，大小2.5M，占据30M内存，这就是dict核心词典的空间效率估量。</div>
<div>    时间复杂度估量更加复杂，不过我们可以简化来说。初级索引需要多少时间？O(1)量级，毋庸置疑。问题是二级词典的复杂度，异常难算。凑合一下，按照比较6.8次计算（因为必须通过遍历才能知道全部的匹配）索引出一个句子所有的完整匹配的时间复杂度O应当为O(n)，其中n是平均二级索引宽度。目前而言，实际测量结果，平均6.8。当词汇量大于一定值后，随着词典的加大，这个值基本是线性增加的，我们粗略的可以认为O(n)即是正比于词典大小。</div>
<div>    而后我们顺便给出分词核心算法在处理一句话时的效率估量吧，证明太长，这里写不下。假定句子长度S，词典大小N，匹配数目M，分词算法的时间复杂度量级为O(N*M*S)，有兴趣的可以帮我复核一下，这个证明颇为困难，不知道有没有证错。在实际运行的时候，匹配数目会跟着词典的增长而增长，而句子长度则相对固定。当然，明眼人一眼就可以看出，所谓匹配数据随着词典增长而增长，其中并不是正比的。而是O(1)&lt;O&lt;O(n)。因此我们可以看作时间复杂度为O(N)&lt;O&lt;O(N^2)，具体是什么，做不出来。</div>
<div>    然后是纯粹的tied tree的性能估量。讲到tied tree，我们就必须要提到如何实现一个有效的tied tree。实际上纯粹用区域哈希映射太浪费内存了，而顺序查找太浪费时间。比较折衷的办法还是只有——dynamic hash table。</div>
<div>    不过这次我们就可以控制一下哈希表的大小了。对于大小不超过6W的哈希，我建议采用crc32，虽然离散度并不高，但是作为一个近似填满的hash table的hash key足矣（这点需要实际考察一下）。如果是自己实现，表项直接存字符串，连指针都不需要，采用开链法。总计大小1M即可以保存所有的一级数据。</div>
<div>    二级数据就无法这么偷懒了，因为二级结构中字符串长度不定。但是以数据展开大小只有2.4M来看，无论这一级别如何扩张，字符串本身大小不应当超过3M。开链法一个节点24字节，平均填充率0.5计算，14个表项一个词典（这个也可以自行控制了），336个字节一个词典，乘以19K个dict。大约6.23M。127K个频率数据1M，这是常规占用。</div>
<div>    以上总计，初级词典本身占用1M，二级结构本身占用10M，不超过20M应当就可以构建起一个高效的核心数据结构。由于实现类似，时间复杂度也类似，就不详细推论了。</div>
<div>    以上还有一点可改进之处，dict作为二级存储的绝对劣势在于，必须要对比全部词典才能确定完全匹配数量，于是时间复杂度正比于词典大小。严格的tied树只需要沿着顺序进行几次索引即可，复杂度取决于词语长度——基本来说和词典大小无关。按照这个推论，实现一个紧凑的，高效的二级小结构，可能比较有利于减小总体大小，增加工作速度。</div>
]]></content:encoded>
			<wfw:commentRss>http://shell909090.com/blog/2012/04/segment%e7%9a%84%e6%a0%b8%e5%bf%83%e6%95%b0%e6%8d%ae%e7%bb%93%e6%9e%84%e7%a9%ba%e9%97%b4%e5%92%8c%e6%97%b6%e9%97%b4%e6%95%88%e7%8e%87%e4%bc%b0%e9%87%8f/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>赞一下京东</title>
		<link>http://shell909090.com/blog/2012/04/%e8%b5%9e%e4%b8%80%e4%b8%8b%e4%ba%ac%e4%b8%9c/</link>
		<comments>http://shell909090.com/blog/2012/04/%e8%b5%9e%e4%b8%80%e4%b8%8b%e4%ba%ac%e4%b8%9c/#comments</comments>
		<pubDate>Tue, 10 Apr 2012 19:18:48 +0000</pubDate>
		<dc:creator>shell</dc:creator>
				<category><![CDATA[其他]]></category>

		<guid isPermaLink="false">http://shell909090.com/blog/?p=2136</guid>
		<description><![CDATA[    昨天觉得背不舒服，买了个按摩器，200。     10点下单，下午两点就送到了，效率不错。     但是用了20分钟，不动了。照说明冷却了一阵，还是不动，遂报换货。     下午四点打电话，10分钟后就来电确认了，五点来了个人，把东西拿走了。     我要求换货，目前页面写的是退货，不知道会不会把新品送来。     不过效率很不错呢。]]></description>
			<content:encoded><![CDATA[<p>    昨天觉得背不舒服，买了个按摩器，200。
<div>    10点下单，下午两点就送到了，效率不错。</div>
<div>    但是用了20分钟，不动了。照说明冷却了一阵，还是不动，遂报换货。</div>
<div>    下午四点打电话，10分钟后就来电确认了，五点来了个人，把东西拿走了。</div>
<div>    我要求换货，目前页面写的是退货，不知道会不会把新品送来。</div>
<div>    不过效率很不错呢。</div>
]]></content:encoded>
			<wfw:commentRss>http://shell909090.com/blog/2012/04/%e8%b5%9e%e4%b8%80%e4%b8%8b%e4%ba%ac%e4%b8%9c/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

