<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
	
	<channel>
		<title>Mental Studio</title>
		<link>http://mental.8gua.me/mental/index.php</link>
		<description>编程是一门艺术</description>
		<language>chs</language>
		<managingEditor>raptor.zh@gmail.com</managingEditor>
                <copyright>Copyright 2010</copyright>
		<generator>Pivot Pivot - 1.40.7: 'Dreadwind'</generator>
		<pubDate>Sun, 05 Sep 2010 07:42:22 -0400</pubDate>
		<ttl>60</ttl>
		
		
		
		
		<item>
			<title>[小工具]生辰八字计算online（Ver.4）</title>
			<link>http://mental.8gua.me/mental/entry/208/my_weblog</link>
			<comments>http://mental.8gua.me/mental/entry/208/my_weblog#comm</comments>
                        <description><![CDATA[ <p>
	虽然早就听说过web.py，不过之前试过感觉还不太成熟，最近又去看了一下，貌似已经相当不错了，便拿来试了试，发现非常合我胃口，迅速决定抛弃用了一年多的web2py。</p>
<p>
	这些年来从Django, TG1, Pylons, Web2py, TG2一路用过来，web.py是唯一一个web框架让我觉得：这就是我想要的。</p>
<p>
	而理由只有一个：干净。</p>
<p>
	本 来web2py已经相当接近我的要求了，除了它以外的另四个都需要安装，而且除了Django以外都需要easy_install那个家伙来安装一大堆的 依赖包，烦也烦死了，还好现在有VirtualEnv，不然真是搞死人。但是即使有VE也还是烦，每次安装都会碰到这样那样的问题，从来没有一次顺利过。 Django那套模式我不太适应，所以很早就不再用了。Web2py不提了，虽然不用安装这点比其它都好，但是DAL那是相当难用，自带的模板也不好用， 更烦的是URL映射太难看。在这些方面来说，TG/Pylons可以选择模板和ORM，Pylons的URL映射也可以做到Django那么灵活，但是 Pylons除了安装麻烦以外，需要自己做的事情实在太多。</p>
<p>
	然而这些都还不是最根本的原因，最重要的还是它们都不够干净&mdash;&mdash;创建一个空项目也要产生一大堆的代码，光是研究去掉哪些部分就要花N多的时间。</p>
<p>
	而web.py没有这些问题，它不需要安装，不产生任何代码，可以根据需要选择ORM或是模板，非常的清爽干净。</p>
<p>
	于是我用它来改写原来的《<a href="http://mental.8gua.me../entry/186" title="Permanent link to entry '[小工具]生辰八字计算online（Ver.3）'">[小工具]生辰八字计算online（Ver.3）</a>》，并且已经放到了GAE上：</p>
<p>
	<iframe height="400" src="http://we8logpy.appspot.com/fourbar" width="600"></iframe></p>
<p>
	补充一些关于web.py发布到GAE上的几个注意事项：</p>
<p>
	第一、运行程序的语句从原来的</p>
<p>
	app.run()</p>
<p>
	改为：</p>
<p>
	main = app.cgirun()</p>
<p>
	也就是用app.cgirun函数去把GAE默认的main函数替换掉；</p>
<p>
	第二、需要预先把模板编译为Python代码：</p>
<p>
	web/template.py --compile templates</p>
<p>
	第三、在app.yaml里配置一下static和script，方法详见GAE文档。</p>
<p style="text-align: right;">
	推送到<a href="http://www.go4pro.org">[go4pro.org]</a></p> ]]></description>
			<guid isPermaLink="false">208@http://mental.8gua.me/mental/pivot/</guid>
			<category>[下载]</category>
			<pubDate>Fri, 03 Sep 2010 23:38:00 -0400</pubDate>
		</item>
		
		
		
		<item>
			<title>带OAuth的twip安装手记</title>
			<link>http://mental.8gua.me/mental/entry/207/my_weblog</link>
			<comments>http://mental.8gua.me/mental/entry/207/my_weblog#comm</comments>
                        <description><![CDATA[ <p>
	由于9月1日起，某网站不再提供BasicAuth方式的登录，必须使用OAuth，这就给中国网民带来了非常大的不便。因为还有好多第三方都是只支持BasicAuth的。</p>
<p>
	不得已，只能自己弄个twip转一下API了。</p>
<p>
	twip的文档实在是太那什么了，所以安装过程主要参考了这篇《<a href="http://7lemon.info/2010/05/oauth-twip.html">轻松搭建oauth twip（PHP）</a>》，不过不知道是版本问题还是别的原因，装好后出不来timeline，查了半天原来是一个小问题。</p>
<p>
	主要的安装过程就不多废话了，看上面那篇链接就好，下面主要说一些注意事项。</p>
<p>
	说明：全部以twip 3.1.2版本为例。</p>
<p>
	第一是注册twitter application的时候，callback url要写全，类似于： https://yourdomain/twip/callback.php</p>
<p>
	第二是要注意 oauth 目录要有 webserver 用户的写权限（最简单就是设置为777，但这样可能不够安全），但同时这个目录不可以通过web方式访问，即不能挂在任何一个域名下。这点上面那篇有说到，这里强调一下。</p>
<p>
	第三是如果 twip 放的目录不是叫 twip 或者不是用子目录而是子域名的话，要到index.php里去改一下WEBROOT，如上面那篇文章所说。</p>
<p>
	第四个就是我碰到的问题，.htaccess里需要加一行 RewriteBase /twip ，当然，如果你用子域名的话，这个就应该是 RewriteBase /</p>
<p>
	配置好后访问twip首页，点sign in，然后allow一下，回到twip设置一个密码。这个密码是twip提供的BasicAuth密码，不必与你实际帐号密码一样。</p>
<p>
	回到首页能够显示五条timeline内容的话说明成功，否则请查看服务器LOG查找原因。</p>
<p>
	以后使用的话就直接在需要API的地方用 http://yourdomain/twip ，并且使用你的用户名及刚刚在twip上设置的密码（注意这个密码别搞错了）进行BasicAuth登录即可。</p>
<p style="text-align: right;">
	推送到<a href="http://www.go4pro.org">[go4pro.org]</a></p> ]]></description>
			<guid isPermaLink="false">207@http://mental.8gua.me/mental/pivot/</guid>
			<category>[技术]</category>
			<pubDate>Fri, 03 Sep 2010 12:06:00 -0400</pubDate>
		</item>
		
		
		
		<item>
			<title>简单的Delphi对象管理器</title>
			<link>http://mental.8gua.me/mental/entry/206/my_weblog</link>
			<comments>http://mental.8gua.me/mental/entry/206/my_weblog#comm</comments>
                        <description><![CDATA[ <p>
	《<a href="http://mental.8gua.me../entry/205" title="Permanent link to entry '掺和比试'">掺和比试</a>》时得到的一个副产品。</p>
<p>
	原 理很简单，就是创建的对象放到一个池里，暂时不释放，再分配的时候可以重用。对于需要反复大量创建删除同一个类的对象时，或是创建对象成本很高的情况下， 这个东东有一定的作用。另外还弄了一个通用的对象管理，不提供POOL的缓冲，仅提供自动释放，纯粹是为了方便，这个可以不针对特定对象。</p>
<p>
	使用方法：</p>
<pre class="brush:delphi;">
uses objmngr;
...
Type
  TDummy = Class(....
    Constructor Create(...);
    Function Init(...) : TDummy;
    ...
  End;
...
Var
  DummyPool : TMObjPool;
...
Function TDummy.Init(...) : TDummy;
Begin
  ...
  Result := Self;
End;
...
// Pool
Var
  om : IMObjPoolManager;
Begin
  om := TMObjPoolManager.Create(DummyPool, 50);
  d1 := (om.New As TDummy).Init(...);  //  Create new dummy object
  ...
End;  //  om and all new dummy objects will be released automatically
...
// Nopool
Var
  om : IMObjManager;
Begin
  om := TMObjManager.Create(50);
  d1 := om.New(TDummy.Create(...)) As TDummy;
  d2 := om.New(TOther.Create(...)) As TOther;
  ...
End; // om and all managed objects will be release automatically
...
Initialization
  DummyPool := TMObjPool.Create(TDummy, 5000);
...
Finallization
  DummyPool.Free;</pre>
<p>
	注意：因为自动创建对象时无法确定构造函数参数，所以只能调用无参数的构造函数，如需初始化对象，则需要再定义一个Init函数供调用。因为Init函数取代了构造函数的功能，所以还需要它返回Self给调用者。</p>
<p>
	管理单元objmngr.pas源码：</p>
<pre class="brush:delphi;">
unit objmngr;

{$IFDEF FPC}{$mode objfpc}{$H+}{$ENDIF}

interface

uses
  Classes, SysUtils;

Type

TMBucket = Record
    Key : TObject;
    Value : TObject;
end;

PMBucket = ^TMBucket;

TMHashMap = Class(TObject)
Private
    FSize  : Integer;
    FItems : Array Of TMBucket;
Protected
    Function HashFunc(Key : TObject) : Integer;
    Function FindKey(Key : TObject) : Integer;
    Function FindEmpty(Key : TObject) : Integer;
    Function GetItem(Key : TObject) : TObject;
Public
    Constructor Create(ASize : Integer);
    Destructor Destroy; Override;

    Procedure AddItem(Key, Value : TObject);
    Procedure DelItem(Key : TObject);
    Function PopItem(Key : TObject) : TObject;

    Property Items[Key : TObject] : TObject Read GetItem;
End;

TMStack = Class(TObject)
Private
    FData : Array Of TObject;
    FTop  : Integer;
Public
    Constructor Create(ASize : Integer);
    Destructor Destroy; Override;
    Procedure Push(AObj : TObject);
    Function Pop : TObject;
    Function IsEmpty : Boolean;
End;

TMObjPool = Class(TObject)
Private
    FMeta  : TClass;
    FPool  : Array Of TObject;
    FIndex : Integer;
    FMap   : TMHashMap;
    FFree  : TMStack;
Public
    Constructor Create(AMeta : TClass; ASize : Integer);
    Destructor Destroy; Override;

    Function NewObj : TObject;
    Procedure FreeObj(AObj : TObject);
End;

IMObjPoolManager = Interface
&nbsp;&nbsp;&nbsp; Function New : TObject;
End;

TMObjPoolManager = Class(TInterfacedObject, IMObjPoolManager)
Private
&nbsp;&nbsp;&nbsp; FPool : TMObjPool;
&nbsp;&nbsp;&nbsp; FObjs : TMStack;
Public
&nbsp;&nbsp;&nbsp; Function New : TObject; Overload;

&nbsp;&nbsp;&nbsp; Constructor Create(APool : TMObjPool; ASize : Integer = 1000);
&nbsp;&nbsp;&nbsp; Destructor Destroy; Override;
End;

IMObjManager = Interface
&nbsp;&nbsp;&nbsp; Function New(AObj : TObject) : TObject;
End;

TMObjManager = Class(TInterfacedObject, IMObjManager)
Private
&nbsp;&nbsp;&nbsp; FObjs : TMStack;
Public
&nbsp;&nbsp;&nbsp; Function New(AObj : TObject) : TObject; Overload;

&nbsp;&nbsp;&nbsp; Constructor Create(ASize : Integer = 1000);
&nbsp;&nbsp;&nbsp; Destructor Destroy; Override;
End;

implementation

{ TMHashMap }

Constructor TMHashMap.Create(ASize : Integer);
Begin
    FSize := ASize;
    SetLength(FItems, FSize);
    FillChar(FItems[0], FSize * SizeOf(TMBucket), 0);
End;

Destructor TMHashMap.Destroy;
Begin
    SetLength(FItems, 0);
    Inherited;
End;

Function TMHashMap.HashFunc(Key : TObject) : Integer;
Begin
    Result := Integer(Key) Mod FSize;
End;

Function TMHashMap.FindKey(Key : TObject) : Integer;
Var
    i, n : Integer;
Begin
    n := HashFunc(Key);
    Result := -1;
    If FItems[n].Key = Key Then
        Result := n
    Else
    Begin
        i := n;
        Repeat
            i := (i + 1) Mod FSize;
            If FItems[i].Key = Key Then
            Begin
                Result := i;
                Break;
            End;
        Until i = n;
    End;
End;

Function TMHashMap.FindEmpty(Key : TObject) : Integer;
Var
    i, n : Integer;
Begin
    n := HashFunc(Key);
    If Integer(FItems[n].Key) = 0 Then
        Result := n
    Else
    Begin
        i := n;
        Repeat
            i := (i + 1) Mod FSize;
            If Integer(FItems[i].Key) = 0 Then
            Begin
                Result := i;
                Exit;
            End;
        Until i = n;
        Raise Exception.Create(&#39;Map is full!&#39;);
    End;
End;

Function TMHashMap.GetItem(Key : TObject) : TObject;
Var
    i : Integer;
Begin
    i := FindKey(Key);
    If i &gt;= 0 Then
        Result := FItems[i].Value
    Else
        Result := Nil;
End;

Procedure TMHashMap.AddItem(Key, Value : TObject);
Var
    i : Integer;
Begin
    i := FindEmpty(Key);
    FItems[i].Key   := Key;
    FItems[i].Value := Value;
End;

Procedure TMHashMap.DelItem(Key : TObject);
Var
    i : Integer;
Begin
    i := FindKey(Key);
    If i &gt;= 0 Then
    Begin
        FItems[i].Key   := TObject(0);
        FItems[i].Value := Nil;
    End;
End;

Function TMHashMap.PopItem(Key : TObject) : TObject;
Var
    i : Integer;
Begin
    i := FindKey(Key);
    If i &gt;= 0 Then
    Begin
        Result := FItems[i].Value;
        FItems[i].Key   := TObject(0);
        FItems[i].Value := Nil;
    End
    Else
        Result := Nil;
End;

{ TMStack }

Constructor TMStack.Create(ASize : Integer);
Begin
    SetLength(FData, ASize);
    FTop := 0;
end;

Destructor TMStack.Destroy;
Begin
    SetLength(FData, 0);
    Inherited;
end;

Procedure TMStack.Push(AObj : TObject);
Begin
    FData[FTop] := AObj;
    Inc(FTop);
    If FTop &gt;= Length(FData) Then
        Raise Exception.Create(&#39;Queue is full!&#39;);
end;

Function TMStack.Pop : TObject;
Begin
    If FTop = 0 Then
        Raise Exception.Create(&#39;Queue is empty!&#39;);
    Dec(FTop);
    Result := FData[FTop];
end;

Function TMStack.IsEmpty : Boolean;
Begin
    Result := (FTop = 0);
end;

{ TMObjPool }

Constructor TMObjPool.Create(AMeta : TClass; ASize : Integer);
Begin
    FMeta  := AMeta;
    SetLength(FPool, ASize);
    FIndex := 0;
    FMap   := TMHashMap.Create(ASize * 4);
    FFree  := TMStack.Create(ASize);
End;

Destructor TMObjPool.Destroy;
Var
   i : Integer;
Begin
    FFree.Free;
    FMap.Free;
    For i := 0 To FIndex - 1 Do
        FPool[i].Free;
    Inherited;
End;

Function TMObjPool.NewObj : TObject;
Var
    i : Integer;
Begin
    If FFree.IsEmpty Then
    Begin
        Result := FMeta.Create;
        FPool[FIndex] := Result;
        i := FIndex;
        Inc(FIndex);
    End
    Else
    Begin
        i := Integer(FFree.Pop);
        Result := FPool[i];
    End;
    FMap.AddItem(Result, TObject(i));
End;

Procedure TMObjPool.FreeObj(AObj : TObject);
Var
    i : Integer;
Begin
    i := Integer(FMap.PopItem(AObj));
    FFree.Push(TObject(i));
End;

{ TMObjPoolManager }

Constructor TMObjPoolManager.Create(APool : TMObjPool; ASize : Integer);
Begin
&nbsp;&nbsp;&nbsp; FPool := APool;
&nbsp;&nbsp;&nbsp; FObjs := TMStack.Create(ASize);
End;

Destructor TMObjPoolManager.Destroy;
Begin
&nbsp;&nbsp;&nbsp; While Not FObjs.IsEmpty Do
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FPool.FreeObj(FObjs.Pop);
&nbsp;&nbsp;&nbsp; FObjs.Free;
&nbsp;&nbsp;&nbsp; Inherited;
end;

Function TMObjPoolManager.New : TObject;
Begin
&nbsp;&nbsp;&nbsp; Result := FPool.NewObj;
&nbsp;&nbsp;&nbsp; FObjs.Push(Result);
end;

{ TMObjManager }

constructor TMObjManager.Create(ASize: Integer);
begin
&nbsp;&nbsp;&nbsp; FObjs := TMStack.Create(ASize);
end;

destructor TMObjManager.Destroy;
begin
&nbsp;&nbsp;&nbsp; While Not FObjs.IsEmpty Do
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FObjs.Pop.Free;
&nbsp;&nbsp;&nbsp; FObjs.Free;
&nbsp;&nbsp;&nbsp; Inherited;
end;

function TMObjManager.New(AObj: TObject): TObject;
begin
&nbsp;&nbsp;&nbsp; FObjs.Push(AObj);
&nbsp;&nbsp;&nbsp; Result := AObj;
end;

end.
</pre>
<p>
	草草写就，应该还有优化的余地。</p>
<p style="text-align: right;">
	推送到<a href="http://www.go4pro.org">[go4pro.org]</a></p> ]]></description>
			<guid isPermaLink="false">206@http://mental.8gua.me/mental/pivot/</guid>
			<category>[技术]</category>
			<pubDate>Tue, 17 Aug 2010 17:44:00 -0400</pubDate>
		</item>
		
		
		
		<item>
			<title>掺和比试</title>
			<link>http://mental.8gua.me/mental/entry/205/my_weblog</link>
			<comments>http://mental.8gua.me/mental/entry/205/my_weblog#comm</comments>
                        <description><![CDATA[ <p>
	Milo老师搞了一个语言大比试&mdash;&mdash;《<a href="http://www.cnblogs.com/miloyip/archive/2010/07/07/languages_brawl_GI.html">C++/C#/F#/Java/JS/Lua/Python/Ruby渲染比试</a>》。我觉得挺好玩的，本来早就想掺和，只是最近比较忙，现在真是来晚了。</p>
<p>
	不过也没什么能掺和的，因为Milo老师的比试已经很全面了，我也就是提供一点自己的测试数据罢了。</p>
<p>
	硬件：Intel Q8200 2.33G/4G RAM</p>
<p>
	软件：Windows 2003 Server</p>
<p>
	说明：为便于与Milo老师的结论作参照，我这里以GCC版本为基准计算对比系数，其中括号内为換算到Milo老师环境中的相对比值。</p>
<table border="1" cellpadding="1" cellspacing="1" style="width: 865px; height: 78px;">
	<tbody>
		<tr>
			<td>
				语言</td>
			<td>
				编译器</td>
			<td>
				编译运行参数</td>
			<td>
				耗时</td>
			<td>
				对比</td>
			<td>
				内存</td>
		</tr>
		<tr>
			<td>
				C++(OpenMP)</td>
			<td>
				GCC 4.3.4 in Cygwin (32-bit)</td>
			<td>
				-O3 -march=native -ffast-math -fopenmp</td>
			<td>
				5.647</td>
			<td>
				0.27x(0.36x)</td>
			<td>
				4M+</td>
		</tr>
		<tr>
			<td>
				C++</td>
			<td>
				Intel C/C++ Compiler 11.1 (IA32) in Ubuntu 10.04 (32-bit) (VirtualBox 3.2.4, 1CPU, 1GRAM)</td>
			<td>
				默认编译参数</td>
			<td>
				17.08</td>
			<td>
				0.83x(1.09x)</td>
			<td>
				2M+</td>
		</tr>
		<tr>
			<td>
				C++</td>
			<td>
				GCC 4.4.3 in Ubuntu 10.04 (32-bit) (VirtualBox 3.2.4, 1CPU, 1GRAM)</td>
			<td>
				-O3 -march=native -ffast-math</td>
			<td>
				18.71</td>
			<td>
				0.91x(1.19x)</td>
			<td>
				2M+</td>
		</tr>
		<tr>
			<td>
				C++</td>
			<td>
				GCC 4.3.4 in Cygwin (32-bit)</td>
			<td>
				-O3 -march=native -ffast-math</td>
			<td>
				20.64</td>
			<td>
				1.00x(1.32x)</td>
			<td>
				4M+</td>
		</tr>
		<tr>
			<td>
				C++</td>
			<td>
				Microsoft Visual C++ 2010 学习版</td>
			<td>
				/Ox /Ob2 /Oi /Ot /Oy- /GL /Gm- /GS- /Gy /arch:SSE /fp:fast /Gd （不含部分默认参数）</td>
			<td>
				22.59</td>
			<td>
				1.09x(1.44x)</td>
			<td>
				2M+</td>
		</tr>
		<tr>
			<td>
				C++</td>
			<td>
				GCC 3.4.5 in MinGW (32-bit)</td>
			<td>
				-O3 -march=pentium4 -ffast-math</td>
			<td>
				51.19</td>
			<td>
				2.48x(3.27x)</td>
			<td>
				2M+</td>
		</tr>
		<tr>
			<td>
				Java</td>
			<td>
				Java SE 1.6.0_10</td>
			<td>
				-server</td>
			<td>
				55.63</td>
			<td>
				2.69x(3.56x)</td>
			<td>
				70M+</td>
		</tr>
		<tr>
			<td>
				C++</td>
			<td>
				Embarcadero C++ Builder 2010</td>
			<td>
				-P -6 -pr -ff -Vx -Ve -r</td>
			<td>
				55.77</td>
			<td>
				2.70x(3.57x)</td>
			<td>
				3M+</td>
		</tr>
		<tr>
			<td>
				C++</td>
			<td>
				Borland Turbo C++ Explorer</td>
			<td>
				-O2 -Hc -Vx -Ve -x- -RT- -ff -X- -pr -a8 -6 -b-&nbsp; -k- -vi -tWC -tWM- -c</td>
			<td>
				60.00</td>
			<td>
				2.90x(3.84x)</td>
			<td>
				3M+</td>
		</tr>
		<tr>
			<td>
				C++</td>
			<td>
				Borland C++ Builder 6.0</td>
			<td>
				-Hc -P -Vx -Ve -x- -RT- -ff -X- -pr -a8 -6 -b-&nbsp; -k- -vi -tWC -tWM- -c</td>
			<td>
				60.14</td>
			<td>
				2.91x(3.85x)</td>
			<td>
				3M+</td>
		</tr>
		<tr>
			<td>
				Delphi</td>
			<td>
				Embarcadero Delphi 2010</td>
			<td>
				默认编译参数</td>
			<td>
				173.77</td>
			<td>
				8.42x(11.1x)</td>
			<td>
				5M+</td>
		</tr>
		<tr>
			<td>
				Delphi</td>
			<td>
				FreePascal 2.2.4(Lazarus 0.9.28.2b)</td>
			<td>
				默认编译参数</td>
			<td>
				241.25</td>
			<td>
				11.7x(15.4x)</td>
			<td>
				5M+</td>
		</tr>
		<tr>
			<td>
				Delphi</td>
			<td>
				FreePascal 2.4(Lazarus 0.9.28.2b) in Ubuntu 10.04 (32-bit) (VirtualBox 3.2.4, 1CPU, 1GRAM)</td>
			<td>
				默认编译参数</td>
			<td>
				329,19</td>
			<td>
				15.5x(20.5x)</td>
			<td>
				2M+</td>
		</tr>
		<tr>
			<td>
				Delphi</td>
			<td>
				Borland Delphi 7</td>
			<td>
				自己实现的对象管理</td>
			<td>
				429.52</td>
			<td>
				20.8x(27.5x)</td>
			<td>
				5M+</td>
		</tr>
		<tr>
			<td>
				Delphi</td>
			<td>
				Borland Delphi 7</td>
			<td>
				默认编译参数</td>
			<td>
				553.91</td>
			<td>
				26.8x(35.4x)</td>
			<td>
				4M+</td>
		</tr>
	</tbody>
</table>
<p>
	VC学习版不提供OpenMP支持，GCC 4.2以前的版本也不支持，BCC更不用说，故OpenMP只试了Cygwin。</p>
<p>
	增 加了一列内存使用情况。基本上C++都差不多，Java则明显多得多。因为这个程序中涉及大量（数以十亿计）的小object的创建和删 除，JAVA的GC回收内存有一定的滞后性，所以运行时内存占用得会多一点，当然这也有个好处就是节约了不断回收小内存所花费的时间，对速度有一定的帮 助。</p>
<p>
	从结果上看新版本的C++编译器对于代码的优化还是很明显的，同样是GCC，Cygwin的4.3.4就比MinGW的3.4.5好得多&mdash;&mdash;当然BCC是个例外，最新版本的速度也没有超过JAVA。</p>
<p>
	在研究过这个程序的代码以后发现，这个程序对内存管理的要求还是挺高的，对于有GC的VM语言或动态语言来说，实现起来会比较方便，C++的栈对象用起来也还不错（运算符重载更是方便），不过要是用C或DELPHI之类内存需要自己管理的语言就杯具了&mdash;&mdash;如表上所示。</p>
<p>
	关于DELPHI版的说明：</p>
<p>
	因 为这个程序在运行时累计需要创建释放的对象多达15亿，而DELPHI的内存管理有个问题就是缺少自动释放的机制。虽然通过接口的引用计数机制是可以实现 类似的功能，但是需要增加很多不必要的函数调用，这样一来速度反而会大幅下降。现在采用的方式是手工即时释放。可能是因为DELPHI7的堆管理机制不是 很适合这种大量小对象的反复创建释放，运行一会以后速度就慢下来，以致于最后耗时很长。</p>
<p>
	后来我试着自己做了一个对象管理，以POOL的方式 进行管理，速度上略有提高，不过还是不明显。而FreePascal Compiler（FPC）显然有一些额外的优化，速度比我自己管理要快近一倍。但是Delphi 2010的优化更多，比FPC还要快约50%。不过从目标代码上看，D7只有100K，FPC是150K，D2010则是300K，看来后二者可能使用了 大量的INLINE优化&mdash;&mdash;这种优化对这个应用来说很重要。</p>
<p>
	根据POOL反馈的数据显示，Vec对象累计创建：1565329629个，但实际峰值使用量（递归最深的时候）仅：1770个。</p>
<p>
	另外，可以注意到的是，我这里有两个版本是与Milo老师的相同：一个是Cygwin版，一个是JAVA版。其中非OpenMP的Cygwin版比Milo老师慢得很少，但是JAVA版却慢了很多。可见硬件性能的提升对于JAVA程序的帮助比较明显。</p> ]]></description>
			<guid isPermaLink="false">205@http://mental.8gua.me/mental/pivot/</guid>
			<category>[技术]</category>
			<pubDate>Wed, 28 Jul 2010 10:32:00 -0400</pubDate>
		</item>
		
		
		
		<item>
			<title>智障手机访问四方的一种解决方案</title>
			<link>http://mental.8gua.me/mental/entry/204/my_weblog</link>
			<comments>http://mental.8gua.me/mental/entry/204/my_weblog#comm</comments>
                        <description><![CDATA[ <p>
	著名的四方网站(foursquare.com)在上周五不能访问了，当时我正在用手机浏览器切客印(check-in)一个瘟牛(venue)，结果刚输入完内容提交就杯具了。</p>
<p>
	兲朝连这么河蟹的一个网站都容不下，真是太神奇了。</p>
<p>
	因为我手机是比较古老的智障的手机，所以跑不了四方的客户端，只能用浏览器访问，智障机也跑不了VPN客户端，我也没有VPN，于是出门在外不能切客印就成了一个大问题，只能每天回家在电脑上补切，这是很不对的。</p>
<p>
	今天&ldquo;突发奇想&rdquo;（感谢郭嘉，感谢0bug老师）试着给四方弄一个代理，结果居然RP爆发，可耻滴成功了。囧</p>
<p>
	方法其实很简单：</p>
<p>
	首先你要有一个墙外的VPS或是类似的能建立反向代理的条件。然后就是建立一个反向代理。搞定。</p>
<p>
	我的做法是在VPS的apache配置里加了两行（当然前提是需要启用mod_proxy）：</p>
<pre class="brush:plain;">
ProxyPass /mobile/ http://foursquare.com/mobile/
ProxyPassReverse /mobile/ http://foursquare.com/mobile/
</pre>
<p>
	因为四方的mobile页面链接全都是不含域名的，等于就是用你自己的域名换掉了四方的域名。不过四方的链接含有mobile路径，所以你也只能代理在mobile这个路径下。</p>
<p>
	经过这样代理，域名和IP都变了，自然就可以访问了。当然，更安全的办法是使用HTTPS。</p>
<p>
	可惜我对PHP不熟，要是有人能写个PHP的代理程序来代理四方的mobile页面，那么连VPS也不需要了，只要有虚拟主机就可以。</p>
<p>
	至于跑四方客户端的智能手机建议还是去买个VPN吧。</p> ]]></description>
			<guid isPermaLink="false">204@http://mental.8gua.me/mental/pivot/</guid>
			<category>[技术]</category>
			<pubDate>Wed, 09 Jun 2010 10:28:00 -0400</pubDate>
		</item>
		
		
		
		<item>
			<title>不信的是鬼</title>
			<link>http://mental.8gua.me/mental/entry/203/my_weblog</link>
			<comments>http://mental.8gua.me/mental/entry/203/my_weblog#comm</comments>
                        <description><![CDATA[ <p>（警告：本文纯属枪手炒作，慎入）</p>
<p>没想到<a mce_href="http://blog.csdn.net/Raptor/archive/2010/02/05/5290875.aspx" href="http://blog.csdn.net/Raptor/archive/2010/02/05/5290875.aspx">那个RPWT的事</a>

过了两个月，肖老师还有兴趣娱乐大众，又作了一篇《<a mce_href="http://blog.csdn.net/tonyxiaohome/archive/2010/04/02/5444929.aspx" href="http://blog.csdn.net/tonyxiaohome/archive/2010/04/02/5444929.aspx">说MiloYip不是枪手，鬼都不信！</a>

》，真是精神可嘉啊。</p>
<p>今天大家看到此文，呼吁Milo回一篇《说我Milo是枪手，鬼才相信！》，不过Milo说他已经决定不再谈这事，不想破戒。后来MK向周老师推荐我来干这事，虽然最近忙着准备结婚，还是勉为其难挤点时间来掺和一下这个娱乐大众的事情。所谓独乐乐不如众乐乐。</p>
<p>肖老师说鬼都不信Milo不是枪手，这是一种相当高深的文学修辞手法，脑子不好的人很容易就被绕进去了&mdash;&mdash;鬼不信Milo不是枪手，鬼信Milo是枪手，信Milo是枪手的是鬼，不信Milo是枪手的不是鬼，信Milo不是枪手的不是鬼&hellip;&hellip;</p>
<p>绕进去没？我说的没错吧。那么你信不信Milo是不是枪手呢？</p>
<p>事实上在obug事件之前我还不认识Milo，托肖老师的福，因为这个事情让我认识了这么一位牛人。真是要感谢党，感谢国家啊。</p>
<p>因
为肖老师而认识Milo的人可不止我一个，上个月Tinyfool来魔都考察，我们一帮人借机去Milo家大吃了一顿。对了，我们这一帮人就是肖老师所谓
的Milo助威团，现在你更加相信我们都是被Milo收买的了吧？这一顿真是丰盛得很，Milo不但程序写得好，书评写得好，菜也做得一流啊，一桌好菜被
我们几个吃得一干二净。</p>
<p>当然，为了表达我们对肖老师的感谢，我们不但在饭前特别感谢了一下肖老师&mdash;&mdash;在Milo的提醒下，我们同样也先感谢
了国家&mdash;&mdash;还在到Milo家后第一时间围观了肖老师的大作。在Milo三房两厅两卫的豪宅里，摆了两个大书柜，其中一柜都是技术书，而且很多都是英文原版
或影印版，比如高爷爷的TAOCP。肖老师的obug一书便也位列这个书柜中。我们瞻仰过后发现此书已经显旧了，看来Milo对肖老师的大作读得非常仔细
啊。</p>
<p>顺便说一下，Milo住在魔都的一个高档社区，从客厅看出去就是著名的苏州河，你说这样的房子得多少钱？估计肖老师从obug那本书拿到的
全部版税如果都用来租房的话，这样的房子还住不了半年。看来当枪手比写书好赚多了。所以，欢迎大家来加入我们这个枪手助威团，我们的目标是&mdash;&mdash;没有蛀牙！</p>
<p>差点忘记了，那天一块吃饭的还有陈硕，不知道肖老师会不会因此认为陈硕也是枪手团的一份子呢？罪过罪过。算了，为了不给肖老师增加调查的麻烦，我把那天饭局的名单列一下吧：</p>
<p><a mce_href="http://www.cnblogs.com/miloyip/" href="http://www.cnblogs.com/miloyip/">MiloYip</a>

，资深游戏软件工程师，CG专家，代表作：UBI《美食从天而降》，推荐阅读他最近写的《<a mce_href="http://www.cnblogs.com/miloyip/archive/2010/03/29/1698953.html" href="http://www.cnblogs.com/miloyip/archive/2010/03/29/1698953.html" id="ctl06_lnkTitle">用JavaScript玩转计算机图形学</a>

》系列文章。</p>
<p><a mce_href="http://blog.csdn.net/solstice" href="http://blog.csdn.net/solstice">陈硕</a>

，这个就不用介绍了，<span mce_style="color: #999999;" style="color: rgb(153, 153, 153);"><strike>CSDN知名专家</strike>

</span>

<u>《代码大全》译者之一</u>

，连肖老师都服他的。哈哈。</p>
<p><a mce_href="http://tiny4.org/blog/" href="http://tiny4.org/blog/">Tinyfool</a>

，重量级搜索技术专家，<a mce_href="http://www.ginkgotek.com/" href="http://www.ginkgotek.com/">银杏科高公司</a>

联合创始人之一。</p>
<p><a mce_href="http://blog.zhaojie.me/" href="http://blog.zhaojie.me/">Jeffz_cn</a>

，.net技术专家，盛大创新院研究员。</p>
<p><a mce_href="http://krzycube.net/" href="http://krzycube.net/">KrzyCube</a>

，盛大创新院研究员。</p>
<p><a mce_href="http://zbw25.spaces.live.com/" href="http://zbw25.spaces.live.com/">庄表伟</a>

，前印客网CTO，盛大创新院研究员。</p>
<p>我，知名8挂人士。</p>
<p>饭毕我们一帮人还围观了一下Milo的新作，一个很炫的3D DEMO程序，效果真是叹为观止。肖老师真是看走眼了，这哪里是枪手能写出来的程序，炮手都写不出来。</p>
<p>肖老师说：说MiloYip不是枪手，鬼都不信。对的，Milo不是枪手，不信的是鬼。</p>
<p>另致肖老师：</p>
<p>你没在卓越成功买过东西吧？所以卓越不让你评论，只要买过东西就可以评论，并且不是只能评论买过的东西。</p>
<p>再致肖老师：</p>
<p>听说obug卖了3000本，这真是大杯具啊，说明可能有2999人被误导了&mdash;&mdash;当然Milo除外。</p>
<p>另致Milo：</p>
<p>你真是白好心了，友情帮肖老师发了几篇堪误，结果他不感谢你也就算了，还要被他扣黑锅，真是不值啊。</p>
<p>又另：</p>
<p>据肖老师说，看了Milo的BLOG感觉一般，令狐建议肖老师也针对Milo的BLOG写三篇《有点失望&mdash;&mdash;读MiloYip BLOG感觉一般》，写不出三篇那一篇也好。</p><p>再补：</p>
<p>肖老师居然作《<a href="http://blog.csdn.net/tonyxiaohome/archive/2010/04/07/5459760.aspx" mce_href="http://blog.csdn.net/tonyxiaohome/archive/2010/04/07/5459760.aspx">做人，还是要有点骨气才好！</a>》回应了本文，真是让本BLOG蓬荜生辉，让本人不胜惶恐。<br/></p>
<p>在此非常感谢肖老师的祝贺。</p><p>结婚实在是花钱花时间的事情，还好有肖老师在为生活增加乐趣。再次表示感谢。<br/>
最后也要祝福一下肖老师，祝您今后在技术上百尺竿头更进一步，免得再碰到Milo这样的&ldquo;枪手&rdquo;来影响您大作的销量。<br/></p> ]]></description>
			<guid isPermaLink="false">203@http://mental.8gua.me/mental/pivot/</guid>
			<category>[杂谈]</category>
			<pubDate>Fri, 02 Apr 2010 17:37:00 -0400</pubDate>
		</item>
		
		
		
		<item>
			<title>iPhone和Android的开放问题</title>
			<link>http://mental.8gua.me/mental/entry/202/my_weblog</link>
			<comments>http://mental.8gua.me/mental/entry/202/my_weblog#comm</comments>
                        <description><![CDATA[ <p>骨灰级果粉tinyfool最近的传教工作真是相当的努力（用virushuo的话说就是：经典体位），昨天发了一篇《<a href="http://tiny4.org/blog/2010/03/iphone-developer/">关于iPhone平台开发生态我的看法</a>》。</p><p>不过我对iPhone或Android都不熟，只是都把玩过朋友的机器，对于我这种只打电话发短信最多加上网刷刷推的人来说，智能手机是可有可无的，有个智障手机足矣。所以对这二者我都没有很大的兴趣。</p><p>但既然谈到开放的话题，特别是关于PC的开放史，我还是想说两句的。</p><p>tinyfool认为PC的发展并不是因为开放，而恰恰是因为CPU和操作系统的不开放。但我认为并非如此。</p><p>回顾那段历史可以看到，正是因为IBM开放的PC硬件架构导致了兼容机的出现，并最终引爆了PC的流行。所谓兼容机，换到现在就是所谓的<span style="font-weight: bold;">山寨</span>。另外，OS在当时也是开放的，并非MS一家独大，市场上除了MSDOS以外还有PCDOS，COMPAQ-DOS，DRDOS等一堆PC的OS。就算是最不开放的CPU也有兼容的AMD在。</p><p>可以说，没有山寨就没有PC的今天&mdash;&mdash;对比不开放的早年水果就知道了。</p><p>至于说为什么IBM没有赚到钱而MS和INTEL发达了显然与开放与否并无必然联系。</p><p>INTEL
方面是因为指令集的专利问题，并且要山寨CPU是技术门槛非常高的事情。再说到了后期同样AMD也有与INTEL不兼容的自己的扩展指令集，而64位平台
就更不用说了，INTEL的IA64因为与IA32存在兼容性问题，结果AMD占了上位。可见掌握了标准也不能保证永远成功，只要在关键的位置错一步就够
受的，何况之前INTEL在RAMBUS一战中已经犯过一次错误而没有吸取教训&mdash;&mdash;RAMBUS和IA64可都是相对更为不开放的东西。可见不开放可能更
不赚钱。</p><p>OS则跟PC架构一样，DOS时代山寨林立，MS得以发达的原因还在于Windows&mdash;&mdash;在当时，它的确有突出的优势，所以才占了
上位，至于后来的标准升级什么的都是在MS已经取得PC OS的实际垄断地位之后的事情了。MS的成功在于它成功地垄断了PC
OS这一块的市场，只有占了垄断地位才有可能靠不开放多赚钱。这一点与水果的思路相同&mdash;&mdash;扩大市场份额，取得事实垄断地位，然后依靠不开放来赚钱。没有占
据垄断地位之前不开放的话，后果还不知道怎么样呢。<br/></p><p>而IBM的失败在于它占的位置是技术门槛最低的，太容易被山寨了，后来自己搞的
那一套MCA又与原来的架构不兼容。另外，PC架构的后期发展技术实际上都是山寨厂商搞出来的，没IBM什么事。不管开不开放，IBM在PC市场终归是没
什么前途的，因为在这种没什么技术含量的市场上，它肯定竞争不过山寨。只能说IBM不适合干这个，还是弄你的那份很有前途的企业级服务去吧。</p><p>由此可见，PC的历史恐怕是无法作为证据拿来证明iPhone的不开放战略将取得成功的。</p><p>至于说在DELL PC写的程序可以在联想PC运行也未必，如果一个跑windows一个跑linux呢？但换个角度，在PC上写的程序有些也可以在MAC上运行，比如用python写的平台无关程序。</p><p>tiny在推上还说过iPad在五年内可以取代书包，但我还是认为五年内取代书包的更可能是类Kindle的电纸书&mdash;&mdash;山寨iPad可能性不大，但山寨电纸书已经出来了。</p><p>从山寨（兼容）PC到山寨手机，历史一次又一次证明了山寨威武。</p><p>那么对于iPhone目前的成功又是怎么回事呢？</p><p>前
面已经说到，这跟Windows的成功有类似之处&mdash;&mdash;并不是因为它不开放而成功，而是因为在过去几年直到现在，水果在技术和创意上一直遥遥领先于竞争对
手。这一点为它带来了大量的用户，而足够多的用户才能吸引到足够多的开发者，开发出更多的应用则使它的领先优势进一步扩大，如此正反馈循环推动水果从成功
走向更加成功。</p><p>但另一方面，这的确如tiny所说，与水果的软硬件标准不开放有一定的联系。</p><p>为什么PC的开放带来成功，手机不开放反而能成功？</p><p>（本段有修改）<br/>我
想这里主要是因为开放的手机平台结果就是百花齐放，缺乏统一标准。比如有些人喜欢全键盘，有人喜欢数字键盘，有人喜欢全触摸，但是PC都是有键盘的（不过
现在的iPad等MID模糊了这一点）。之所以PC比较没有这样的问题，跟手机的私有性有关。PC在很多时候都是公用或半公用的&mdash;&mdash;比如一家人用一台电
脑，或者学校机房，网吧&hellip;&hellip;但手机几乎是绝对私用的，很少有人会共用一只手机（iPad等MID之所以会与传统PC有如此大的改变，也是由于这类PC实际
上私有性很强）。这就意味着手机与手机之间的兼容性并不是那么重要，于是手机的世界从一开始就是开放而多样的，即使是在比较统一的山寨机平台MTK上也是
如此。手机的这种多样化对于开发人员来说真是梦魇。相比之下iPhone的统一软硬件平台就省事多了&mdash;&mdash;这一点水果像PC。这也是tiny之前说过的主要
理由&mdash;&mdash;统一的平台对于开发人员来说，为水果做开发省事很多。<br/></p><p>另外一个可能有关的是扩展性。手机的扩展性除了插个存储卡以外，其它
的扩展很有限。你不能往手机上插个重力感应或GPS或多点触摸。所以依赖特定硬件的软件在PC上问题不大，用户只要买一个相应的设备插上就行，在手机上就
不行了。于是统一软硬件标准的iPhone在这点上也有优势&mdash;&mdash;这一点水果以外的其它手机没法像PC，所以它们都不如水果成功。</p><p>但我仍然认
为Andriod还是很有希望的，假以时日，它应该能够解决目前面临的种种问题（比如在软件层面实现足够的抽象以便应用软件的开发）而一统山寨，到时就算
扳不倒水果，至少也可以分庭抗礼。倒是NOKIA白占了最大的市场份额却没有弄出个像水果这样的场面还真不是一般的失败啊。</p><p>我之所以不希望
水果一家独大至少有两个理由：第一，我不希望哪天吃饭时，一帮人坐下来掏出手机往桌上一放，十个有九个是iPhone，剩下一个不是iPhone的旁边也
有一个iTouch，那样的世界真是太杯具了；第二，这是个人爱好，我还是喜欢有键盘的手感，全键盘或数字键盘均可。<br/></p><p>最后我想到了阮一峰最近对Android的批评。与tiny认为Andriod太开放而不能成功相反，阮一峰认为Andriod会因为不够开放而不能成功。</p><p>这种对比很有意思。<br/></p> ]]></description>
			<guid isPermaLink="false">202@http://mental.8gua.me/mental/pivot/</guid>
			<category>[杂谈]</category>
			<pubDate>Thu, 11 Mar 2010 17:37:00 -0400</pubDate>
		</item>
		
		
		
		<item>
			<title>Twisted开发Web应用笔记</title>
			<link>http://mental.8gua.me/mental/entry/200/my_weblog</link>
			<comments>http://mental.8gua.me/mental/entry/200/my_weblog#comm</comments>
                        <description><![CDATA[ <p>
	Twisted是一个功能极为强大的异步网络应用开发库&mdash;&mdash;当然是Python的。印象中大概也就只有ACE有这么强悍，但Twisted在易用性方面要好很多&mdash;&mdash;这其中当然少不了Python的功劳（ACE是用C++的）。</p>
<p>
	但 Python也有其缺点，其中之一就是因为GIL的存在使得用Python写多线程应用的意义不大，那么对于像Twisted这样基于Reactor模式 实现的单一Event Loop的应用开发环境来说，就有一点局限：整个应用（或者说整个进程）都必须围绕着reactor来。这样的话做一些纯后端的应用是没什么问题，比如像 网页爬虫（Scrapy就是基于Twsited的）一类的应用。但这显然不够，很多应用还是需要有前端界面的&mdash;&mdash;比如像BT、电驴这样的下载工具。 MLDonkey采用的方法就是提供一个WEB的管理界面来与用户交互&mdash;&mdash;当然，MLDonkey并不是用Python开发的。</p>
<p>
	这是一个很好的思路。所以Twisted提供了一套WEB开发环境以实现这样的目的。</p>
<p>
	关于twisted.web部分的开发，<a href="http://twistedmatrix.com/documents/current/web/">官方的文档</a>显得太过于简单了，特别是连基本的request对象的参考文档都没有。还好gashero整理了一部分在《<a href="http://gashero.yeax.com/?p=22">Twisted的WEB开发</a>》，引用一下（有补充）：</p>
<p>
	channel ：包含上级的HTTP协议对象。<br />
	transport ：通信对象。<br />
	method ：HTTP方法，如GET和POST。<br />
	uri ：全部请求的URI。<br />
	path ：具体的请求路径，不含参数。<br />
	args ：请求参数，包括URL参数和POST参数。格式如 {&rsquo;key&rsquo;:[&rsquo;val1&prime;,&rsquo;val2&prime;],} 。<br />
	received_headers ：请求报文的头字段。<br />
	received_cookies ：请求报文的cookie。<br />
	content ：请求报文的实体主体，文件对象。<br />
	clientproto ：发出请求的客户端的HTTP版本。<br />
	client ：请求的客户端地址对象，包括type、host和port属性，分别记录协议（这里固定为TCP）、IP和端口号<br />
	host ：本机接收请求的地址对象<br />
	getHeader(key) ：获取请求的头字段。<br />
	getCookie(key) ：获取请求的cookie。<br />
	getAllHeaders() ：所有请求的头字段字典，就是返回received_headers。<br />
	getRequestHostname() ：请求的host字段，不含端口号。<br />
	getHost() ：原始请求的通信地址，返回host。<br />
	getClientIP() ：获取客户端IP。<br />
	getUser() ：获取basic验证中的用户名。<br />
	getPassword() ：获取basic验证中的密码。<br />
	getClient() ：获取客户端地址对象</p>
<p>
	一个最基本的Web应用如下：</p>
<pre class="brush: python;">
from twisted.web import server, resource
from twisted.internet import reactor

class Simple(resource.Resource):
    isLeaf=True
    def render_GET(self, request):
        return &quot;Hello, world!&quot;

reactor.listenTCP(8080, server.Site(Simple()))
reactor.run()
</pre>
<p>
	然后运行起来就可以通过URL：http://localhost:8080 访问这个程序的页面了。</p>
<p>
	注意其中的的isLeaf是必须的。不过也还有另一种方法可以实现同样的功能：</p>
<pre class="brush:python;">
from twisted.web import server, resource
from twisted.internet import reactor

class Simple(resource.Resource):
    def __init__(self):
        resource.Resource.__init__(self)
        self.putChild(&quot;&quot;, self)

    def render_GET(self, request):
        return &quot;Hello, world!&quot;

reactor.listenTCP(8080, server.Site(Simple()))
reactor.run()</pre>
<p>
	这个方法好理解，就是把这个对象挂到请求链接的根目录上。以此类推就可以实现带子目录请求的页面：</p>
<pre class="brush:python;">
from twisted.web import server, resource
from twisted.internet import reactor

class ChildSimple(resource.Resource):
    isLeaf=True
    def render_GET(self, request):
        return &quot;Hello, child!&quot;

class Simple(resource.Resource):
    def __init__(self):
        resource.Resource.__init__(self)
        self.putChild(&quot;&quot;, self)
        self.putChild(&quot;child&quot;, ChildSimple())

    def render_GET(self, request):
        return &quot;Hello, world!&quot;

reactor.listenTCP(8080, server.Site(Simple()))
reactor.run()</pre>
<p>
	现在可以通过URL：http://localhost:8080/child 访问这个子页面了。不过生成子页面还有一个动态的办法：</p>
<pre class="brush:python;">
from twisted.web import server, resource
from twisted.internet import reactor

class ChildSimple(resource.Resource):
    isLeaf=True
    def __init__(self, id):
        resource.Resource.__init__(self)
        self.id=id

    def render_GET(self, request):
        return &quot;Hello, No. %s visitor!&quot; % self.id

class Simple(resource.Resource):
    def __init__(self):
        resource.Resource.__init__(self)
        self.putChild(&quot;&quot;, self)

    def render_GET(self, request):
        return &quot;Hello, world!&quot;

    def getChild(self, path, request):
        return ChildSimple(path)

reactor.listenTCP(8080, server.Site(Simple()))
reactor.run()</pre>
<p>
	现在可以试试URL：http://localhost:8080/1234 访问了。其中1234可以换成任何数字（实际上上面的程序对此未作限制，即使输入任何字符也是可以的）。</p>
<p>
	接下来是静态内容的使用：</p>
<pre class="brush:python;">
from twisted.web import server, resource, static
from twisted.internet import reactor

class Simple(resource.Resource):
    def __init__(self):
        resource.Resource.__init__(self)
        self.putChild(&quot;&quot;, self)
        self.putChild(&quot;static&quot;, static.File(&quot;/var/www/htdocs&quot;))

    def render_GET(self, request):
        return &quot;Hello, world!&quot;

reactor.listenTCP(8080, server.Site(Simple()))
reactor.run()</pre>
<p>
	访问一下URL：http://localhost:8080/static 试试就知道了。</p>
<p>
	这 些对于Web开发都是些基本的功能，稍微复杂一点的网页要做起来还是很痛苦的。但是Python是很灵活的东西，资源也很丰富，所以实际上问题也不大。比 如在getChild方法里加上routing的实现，再加一个mako一类的模板，功能立即强大很多（貌似搞得像Pylons了）&mdash;&mdash;只是数据库操作还 是需要谨慎一些，简单地加上SQLAlchemy之类的ORM也不是不行，但是它对数据库的访问是阻塞式的，可能导致Twisted应用的性能下降很大。</p>
<p>
	所幸的是一般来说为Twisted应用增加Web交互界面很少还有需要操作数据库的，即使必须要有，Twisted也提供了异步的数据库访问接口&mdash;&mdash;虽然功能不可能像SQLAlchemy那么强大，对于简单的应用应该也足够了。</p>
<p>
	虽然WEB界面已经很方便了，但也许还会有人想要用交互式GUI，这也没问题。Twisted的Web库提供了对XMLRPC和SOAP的支持。以简单一些的XMLRPC为例：</p>
<pre class="brush:python;">
from twisted.web import server, resource, xmlrpc
from twisted.internet import reactor

class XREcho(xmlrpc.XMLRPC):
    def xmlrpc_echo(self, bar):
        return bar

reactor.listenTCP(8080, server.Site(XREcho()))
reactor.run()</pre>
<p>
	客户端的调用方式是：</p>
<pre class="brush:python;">
import xmlrpclib

s = xmlrpclib.Server(&quot;http://localhost:8080/&quot;)
s.echo(&quot;Hello!&quot;)</pre>
<p>
	上面的代码执行后将回显。</p>
<p>
	实 际上XMLRPC对象也是一种Resource，所以也可以简单地用putChild放到子目录下去。或者如果需要对xmlrpc的request进行控 制&mdash;&mdash;比如增加authentication或者其它的客户端调用限制，可以在_cbRender方法里实现，具体可参考web.xmlrpc的源码。</p>
<p>
	关于用Twisted进行Web开发的更多内容请参考官方文档和源码。</p> ]]></description>
			<guid isPermaLink="false">200@http://mental.8gua.me/mental/pivot/</guid>
			<category>[技术]</category>
			<pubDate>Tue, 09 Mar 2010 16:07:00 -0400</pubDate>
		</item>
		
		
		
	</channel>
</rss>
