[测试]web性能测试分析-工具篇

mikel阅读(1108)

用于Web性能分析的工具还有很多,以下只不过是我所略知的几种,如各位有使用未列出性能工具,请跟帖共享。以下软件都可容易下载到.我建议全部下载,根据自已的需求,选择最适合自己的一款,呵呵,这个工作比较累呀。

微软官方免费软件:

CLRProfiler

是一个可以用于分析.NET程序行为的工具。可用其分析垃圾回收器堆正在发生的事情,例如什么方法分配了什么类型的对象?另外,还提供了调用图(call graph)功能用于显示哪个方法调用了哪个方法

Microsoft Web Application Stress Tool

Microsoft Web Application Stress Tool 是由微软的网站测试人员所开发,专门用来进行实际网站压力测试的一套工具。透过这套功能强大的压力测试工具,您可以使用少量的Client端计算机仿真大 量用户上线对网站服务所可能造成的影响,在网站实际上线之前先对您所设计的网站进行如同真实环境下的测试,以找出系统潜在的问题,对系统进行进一步的调 整、设置工作。

Microsoft Application Center Test

Microsoft Application Center Test是vs.net2003企业版自带的一个测试工具.使用它可以收集性能信息.确定WEB应用程序的容量.也可以创建测试,模拟同时从WEB应用程 序请求网页的多个用户.这些模拟测试有助于确定应用程序的稳定性.速度和响应能力.

商业软件(其实试用30天已经足够用了):

dotTrace

是个很不错的分析工具(Profiling Tool),可以分析windows form和ASP.NET ,它能够快速分析、过滤、函数查找(快速定位function,并且导航)和查看源码.

试用版下载(http://www.red-gate.com/products/ants_profiler/index.htm)

ANTS Profiler

一个检测基于.Net Framework的任何语言开发出的应用程序的代码性能的工具。她可以通过记录每行代码花费的时间,来帮助你优化程序的执行,而且可以用很多种格式来探测应用程序中效率不好的区域。ANTS Profiler还可以分析应用程序的内存使用状况,她就是通记录每个对象分配的内存空间大小,来提供很多种报告样式给开着这察看哪个对象或者类占用了最多的内存,从而可以帮助你优化内存的使用。

试用版下载(http://www.red-gate.com/products/ants_profiler/index.htm)

AQTime

一款功能强大的Code Profiler工具,有很多种代码分析方式,一般主要是用它来做性能分析,目的是定位程序性能瓶颈,然后再有针对性地进行优化。函数追踪功能,能看清函数的调用,而且能定位到行级,确定系统性能的瓶颈。

试用版下载(http://www.automatedqa.com)

.NET Memory Profiler

是NET Memory Profiler是一款强大的.net 内存跟踪和优化工具。

DevPartner Studio Professional Edition

是一套功能非常强大全面性的软件开发除错工具,协助程序开发人员使用微软Visual Studio .NET与Visual Studio 6.0开发应用程序与WebService。 其功能包括扫描程序找出程序码潜在的问题,侦测执行阶段的错误,程序执行效能分析,分散式应用系统问题分析,与程序码测试涵盖度分析等。支持微软的 Visual Studio .NET、Native Windows或是两者混合使用的应用程序,加速应用程序的开发,提高应用系统的稳定性与执行效能。

LoadRunner

是否目前国内最多人用的压力测试工具,感觉与.net搭配不是很好。

[C#]URL中的中文编码

mikel阅读(1019)

问题来源:
    正在研究一个程序,输入一个关键字,能够把这个关键字发送到Google,yahoo等搜索引擎,进行搜索,然后打开结果网页。原理很简单。比如在 Google搜索China,搜索结果页面的URL就是“http://www.google.com/search?hl=zh-CN&q=China&lr=”。只要替换红颜色的内容,就可以按照不同的关键字搜索。
但是如果关键字是中文,就会出现问题。比如在google搜索“中国”,Url是“http://www.google.com/search?hl=zh-CN&newwindow=1&q=%E4%B8%AD%E5%9B%BD&lr=”。汉字“中国”被按照UTF-8的格式进行编码。
不仅汉字进行编码,一些特殊字符也会进行编码。比如搜索“C#”,URL是“http://www.google.com/search?hl=zh-CN&newwindow=1&q=C%23&lr=”。
一般来说,国外的网站都是按照UTF-8编码,而“百度”是按照“GB2312”进行编码的。比如搜索“中国”,URL是“http://www.baidu.com/s?wd=%D6%D0%B9%FA&cl=3”
我们对比一下:C#中国的编码

编码 结果 网站
UTF-8 C%23%E4%B8%AD%E5%9B%BD Google
GB2312 C%23%D6%D0%B9%FA BaiDu

总结:
UTF-8中,一个汉字对应三个字节,GB2312中一个汉字占用两个字节。
不论何种编码,字母数字都不编码,特殊符号编码后占用一个字节。
开始编程:

        public static string UrlEncode(string str, string encode)
        
{
            
int factor;
            
if (encode == "UTF-8")
                factor 
= 3;
            
if (encode == "GB2312")
                factor 
= 2;
            
//不需要编码的字符
            string okChar = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-*@";
            System.Text.Encoder encoder 
= System.Text.Encoding.GetEncoding(encode).GetEncoder();
            
char[] c1 = str.ToCharArray();
            System.Text.StringBuilder sb 
= new System.Text.StringBuilder();
            
//一个字符一个字符的编码
            for (int i = 0; i < c1.Length; i++)
            
{
                
//不需要编码
                if (okChar.IndexOf(c1[i]) > 1)
                    sb.Append(c1[i]);
                
else
                
{
                    
byte[] c2 = new byte[factor];
                    
int charUsed, byteUsed; bool completed;

                    encoder.Convert(c1, i, 
1, c2, 0, factor, trueout charUsed, out byteUsed, out completed);

                    
foreach (byte b in c2)
                    
{
                        
if (b != 0)
                            sb.AppendFormat(
"%{0:X}", b);
                    }

                }

            }

            
return sb.ToString().Trim();


        }

后来发现更简单的方法。

//按照UTF-8进行编码
string tempSearchString1 = System.Web.HttpUtility.UrlEncode("C#中国");
//按照GB2312进行编码
string tempSearchString2 = System.Web.HttpUtility.UrlEncode("C#中国",System.Text.Encoding.GetEncoding("GB2312"));

大家直接用第二种方法就行了。

[AS]基于豆瓣API的六度拓扑

mikel阅读(918)

6DTOP源代码版本1.0系列


欢迎各位朋友对六度拓扑的喜爱,六度拓扑应该算是我互联网实验中第一个称得上成熟的作品。
无论从构思,还是到创作的过程,直到最后的产品,我都是很满意的。
当然,最先要感谢还是豆瓣网能放出这个通过ID来查找朋友的API,没有这个API就没有这个作品。
那么大的一个网站,用自己服务器和带宽把API开放出来供大家使用,这种奉献的精神本身就很值得称道,所以,我觉得放出自己的源代码是很应该的事,而且,其中也一定会有很多的好处。
我在大学时代读过Linus Torvalds
自传<乐者为王>,我不敢奢谈自己的编程水平有多高,但我和Linus Torvalds一样,都对编程活动充满热情。对我而言,程序设计最大的乐趣就在于创作,这和歌手写歌,作家写文章从某种程度上是具有一致性,最终的作品是否能得到大家的认可,将是我最大的颀慰。
我喜欢李宗盛大哥的一句话:“一把琴,在它交在一个音乐人手中之前,基本上是个废物,它一定要落在一个做音乐的人手中,它才有了生命。”—–与所有喜欢创作的朋友共勉。
——————————————————————-
好,书归正传,让我们说说代码吧:
1.首先要说的是关于程序编译环境,程序是用flash cs3编译的,虽然里面有一此看上去和flex有关的文件,但那只是我用flex作为编辑器所产生的"副产品",我采用开发方式是flash作为编译器和界面设计工具,而flex作为代码编辑器。
flash cs3 下载地址
至于flash所采用的开发语言——ActionScript 3,如果你学过像JAVA,C++这样的OOP语言,从语法能很轻松的理解。
2.程序之核心
2.1
程序最重要的一个部分就是"轨道",参UIEntity.Orbit

轨道图示
从图中,可以看出,结点是被一个吸引到轨道上去的。
而轨道的吸引是分阶段,第一阶是RANDOM_ATTRACT,第二阶段是ARRANGE。
RANDOM_ATTRACT:由于在二度及以上的朋友中,无法在搜索完成某度的所有朋友前,获知其朋友的数目,因此,为了让头像可以尽可能的均匀排列,需要根据当前已搜索的某度朋友的数目来进行,这个阶段称为RANDOM_ATTRACT。
ARRANGE:这个阶段就很清楚了,某个朋友的某度朋友全部完成时,让其朋友尽可能的均匀排列。
轨道的实现用的是DFA(有限自动机),其实我这里的实现是很简单的,就是在一个可以被反复执行的函数,如foo中,加swith(status)这样的语句,GOT IT?
DFA是我在交互应用中非常喜欢用的东西,我对它喜欢的不得了,他真是个既简单,又有效的思想。
如果我说程序的核心就这点的话,肯定有人要扔蕃茄了,但事实就是这样,这个就是程序之核心,当然,实现这个核心的某些细节还是很值得讨论下的。
2.2Orbit吸引之实现
Orbit自己只负责完成吸引的动作,但由谁负责把结点push进某个orbit呢?这就需要由另一个自动机来做,参看DouBanFriendTopology类(主类)中的
enterFrameFun(evt:Event):void函数的实现
它的基本思想是这样的,将当前中心点的一度用户装入一个队列中,
然后,每隔50ms左右(出于性能考虑),从队列(参AS3STL.EQueue)Q的头部取出一个用户F->
     查看用户F的朋友是否已全部获取(由于豆瓣朋友的XML一次只能请求50个,所以当朋友大于50时,要多次请求)。
     YES
全部获取 : 把用户F用队列Q里取出,查看它的所有朋友结点。
         IF  
朋友结点i未被使用
              加入队列Q的尾部      
         ELSE
直接丢弃此结点,这里为了避免重复结点,
              如a-b是好友,b-c是好友,而c-a又是好友

        
     NO
未全部获取: 等待
这是一个很简单但很有效的算法,不是吗?
因为这里,只要不停止抓取,用户的朋友,朋友的朋友…是会一直获取(抓取的过程参
DouBanFriendTopology类中的ClawMainFun(event:TimerEvent):void)下去的,也就是说,队列是无限延伸(除非把N度朋友全抓完或到某度时所有人都没有朋友了),对于这样一种动态的数据的情况,本来是很麻烦的,但这里用一个"查看用户F的朋友是否已全部获取"就优雅的处理了这一情况,个人对此颇为满意。
3OK,关键的部分就先介绍到这里了,先讲讲程序的组织:
Douban_Fri_Topology.fla 程序主文件,编辑它即可观看6度拓扑。
DouBanFriendTopology.as 程序的主类。
OriginalGraph.fla       程序的原型图所在文件,用于先期设计。
about.swf              点 击About后播放的flash文件,里面用到了我最喜欢的美                       国选秀结目<学徒>的背景音 乐。(第一帧被设为暂停了,要通                        过程序控制播放)
——————————————————————

AS3STL                 
自写的AS3 STL包,目前仅有一个队列(以前有一个较全的
AS2STL,有stack,tree,graph啥的,过一阵改写)。
               
ComuEntity             
通讯实体类,用来请求XML,并返回相应结果,        
Fetch_Friend.as是用来获取朋友数据的。
而Fetch_People.as则是在搜索时用来获取个人信息(ID)的,主要用在如http://www.6dtop.com/search.asp?id=ahbei上。
EventCenter
CEventCenter, 这是一种形之有效的自写消息的机制,当你从一个“深处”,比方说obj1.obj2.obj3.xxx发出一个消息给obj100,通过这样一种直接管理 -派发的机制,有效的解决了这个问题,无论语言是否带什么dispatch之类的自定义消息机制,都可以用这种基于函数实现的消息来做。
CGData
用来存放一些全局数据,UserList是一个全局的异质(就是不会有重复的)用户列表。
Model
用来定义一些仅和数据相关的模型,如这里的UserModel.
UIEffect
效果包,DragEffectVM是我非常颀常的一个自写鼠标拖动管理类,他带来了非常高的便捷性和灵活性。
UIEntity
UI 实体包,其中的Orbit(轨道)和UserNode(用户结点)最为重要,而ToolBar中包括了ScaleToolBar(左侧形变工 具),Upline(上部工具),ButtomLine(下部工具),这里用到了在flash制作的一些元件,在FLEX里由于无法识别,会报错(由于没 有编译成.swc),不用理会,因为这里是用flash进行编译的。
Utils
实用类包,ArrayUtil,数组辅助方法。
WebService
WebService包,SWebService,包含了请求的地址等。
——————————————————————
about_swf文件夹,包含了about flash的源文件。
由于about.swf第一帧被设为了暂停,所以,可以使用loader.swf
——————————————————————
说了大半天,终于来点实惠的了,6DTOP 源码1.0版本,跟大家分享了
http://www.6dtop.com/open/v1.0/6dtop.source.1.0.rar

[Adobe]Adobe发布的Adobe CS4下载

mikel阅读(746)

感谢abc的投递
新闻来源:原创
几天前Adobe 官方宣布CS4推出,正式版会在10月份发售,在国外网站找了半天,终于找到Flash CS4的试用版,BT了半天,而非正式发售版。
好东西当然与大家一起分享,在这里笔者就为大家评测部分Flash CS4的功能及界面,更多东西自行“哇”。

一、安装画廊
在网上下载后文件是Adobe Flash CS4 Install Americas.exe,点击选择解压,解压完成,安装开始,以下是截图;






开始菜单

桌面右键

二、功能
2.1 – 主界面

1、CS4的菜单栏进行了界面优化,你会发现更方便的使用;
2、快速更换布局,默认为Essentials,共分为6种布局,方便不同的用户群;
3、把常用工具和属性及图层库集合在一起,更能提升效率;
4、动画的关键帧放在最下方,你是否会发现在下方比上方好?
2.2 – 利用Flash Cs4 AIR 创建跨平台应用程序
细心的朋友,在上面看安装时的画廊就知道,组件里多了Adobe AIR,在“文件“里我们可以看到多了一项AIR Settings,有了发布AIR程序,当然我们可以轻松的创建AIR程序。
2.3 – 分享我的屏幕
大家还记得原来微软发布过Share桌面软件,这个功能跟微软的相似,点击“文件” –“Share my screen”,然后登录,如图。

登录完成后,自动启动Adobe Connectnow程序,把上面的地址发送给对方,也可利用Email进行发送;

多功能协作

2.5 – 崩溃的后果
这年代崩溃也不需要标题,直接意外事故更好,流行。

三、Adobe Media Encode Cs4
利用Media Encoder转换吧,记得原来需要单独下载,现在集成到一起来啦。

四、更多截图画廊
4.1 – Adobe Extension Manager

4.2 – Adobe Desktop

4.3 – Adobe Device Central CS4

4.4 –Adobe ExtendScript Toolkit CS4
 
4.5 – Adobe Drive CS4

结论
试用了Flash CS4过后,感觉变化最大就是优化了界面,不过遗憾的是Flash CS4测试版中的语言很乱,如 Adobe Extension Manager CS4和Adobe Drive CS4是中文的,Flash CS4 却是英文的,安装也是全中文,不过遗憾的是只能选择4种语言,里面并没有包含中文,一直在想。Adobe应该中文集成到默认语言,这样更多朋友会体验新产 品。

Flash CS4最值得让我们选择他的几点好处:

1.CS4带来了最新的AIR程序创建,也许以后你创建安装程序你会选择AIR(自己原来就有这种想法,AIR的安装流程做得非常的漂亮);
2.优化后的界面看起来更漂亮,更适合多显示器使用,默认布局对屏幕大的用户提供了良好的视觉等;
当然更多功能还需大家亲自体验,更多新鲜功能尽在CS4中,一起期待吧。真想ZzZzZz/..
Flash Cs4测试版下载:QQ中转站   (提取码 57f33f01)
Flash Cs4破解文件:QQ中转站  (提取码 e88b49ef)

[C#]泛型中的强制类型转换

mikel阅读(1473)

泛型类型中的变化(C# 编程指南)

更新:2007 年 11 月

C# 中添加泛型的一个主要好处是能够使用 System.Collections.Generic 命名空间中的类型轻松地创建强类型集合。例如,您可以创建一个类型为 List<int> 的变量,编译器将检查对该变量的所有访问,确保只将 List<int> 添加到该集合中。与 C# 1.0 版中的非类型化集合相比,这是可用性方面的一个很大改进。

遗憾的是强类型集合有自身的缺陷。例如,假设您有一个强类型 List<object>,您想将 List<int> 中的所有元素追加到 List<object> 中。您可能希望能够如下面的示例一样编写代码:

List<int> ints = new List<int>();
ints.Add(1);
ints.Add(10);
ints.Add(42);
List<object> objects = new List<object>();
// doesnt compile ints is not a IEnumerable<object>
//objects.AddRange(ints); 

在这种情况下,您希望能够将 List<int>(它同时也是 IEnumerable<int>)作为 IEnumerable<object> 处理。这样做看起来似乎很合理,因为 int 可以转换为对象。这与能够将 string[] 当作 object[](现在您就可以这样做)非常相似。如果您正面临这种情况,那么您需要一种称为泛型变化的功能,它将泛型类型的一种实例化(在本例中为 IEnumerable<int>)当成该类型的另一种实例化(在本例中为 IEnumerable<object>)。

由于 C# 不支持泛型类型的变化,所以当遇到这种情况时,您需要尝试几种可能的方法来解决此问题。对于最简单的情况,例如上例中的单个方法 AddRange,您可以声明一个简单的帮助器方法来为您执行转换。例如,您可以编写如下方法:

// Simple workaround for single method
// Variance in one direction only
public static void Add<S, D>(List<S> source, List<D> destination)
where S : D
{
foreach (S sourceElement in source)
{
destination.Add(sourceElement);
}
}

它使您能够完成以下操作:

// does compile
VarianceWorkaround.Add<int, object>(ints, objects);

此示例演示了一种简单的变化解决方法的一些特征。帮助器方法带两个类型参数,分别对应于源和目标,源类型参数 S 有一个约束,即目标类型参数 D。这意味着读取的 List<> 所包含的元素必须可以转换为插入的 List<> 类型的元素。这使编译器可以强制 int 可转换为对象。将类型参数约束为从另一类型参数派生被称为裸类型参数约束。

定 义一个方法来解决变化问题不算是一种过于拙劣的方法。遗憾的是变化问题很快就会变得非常复杂。下一级别的复杂性产生在当您想要将一个实例化的接口当作另一 个实例化的接口时。例如,您有一个 IEnumerable<int>,您想将它传递给一个只以 IEnumerable<object> 为参数的方法。同样,这样做也是有一定意义的,因为您可以将 IEnumerable<object> 看作对象的序列,将 IEnumerable<int> 看作 ints 的序列。由于 ints 是对象,因此 ints 的序列应当可以被当作对象序列。例如:

static void PrintObjects(IEnumerable<object> objects)
{
foreach (object o in objects)
{
Console.WriteLine(o);
}
}

您可能希望能够如下面的示例一样调用:

// would like to do this, but cant ...
// ... ints is not an IEnumerable<object>
//PrintObjects(ints);

接口 case 的解决方法是:创建为接口的每个成员执行转换的包装对象。这可能类似于如下示例:

// Workaround for interface
// Variance in one direction only so type expressinos are natural
public static IEnumerable<D> Convert<S, D>(IEnumerable<S> source)
where S : D
{
return new EnumerableWrapper<S, D>(source);
}
private class EnumerableWrapper<S, D> : IEnumerable<D>
where S : D
{

它使您能够完成以下操作:

PrintObjects(VarianceWorkaround.Convert<int, object>(ints));

同样,请注意包装类和帮助器方法的裸类型参数约束。此 系统已经变得相当复杂,但是包装类中的代码非常简单;它只委托给所包装接口的成员,除了简单的类型转换外,不执行其他任何操作。为什么不让编译器允许从 IEnumerable<int> 直接转换为 IEnumerable<object> 呢?

尽管在查看集合的 只读视图的情况下,变化是类型安全的,然而在同时涉及读写操作的情况下,变化不是类型安全的。例如,不能用此自动方法处理 IList<> 接口。您仍然可以编写一个帮助器,用类型安全的方式包装 IList<> 上的所有读操作,但是写操作的包装就不能如此轻松了。

下面是处理 IList<(Of <(T>)>) 接口的变化的包装的一部分,它显示在读和写两个方面的变化所引发的问题:

private class ListWrapper<S, D> : CollectionWrapper<S, D>, IList<D>
where S : D
{
public ListWrapper(IList<S> source) : base(source)
{
this.source = source;
}
public int IndexOf(D item)
{
if (item is S)
{
return this.source.IndexOf((S) item);
}
else
{
return -1;
}
}
// variance the wrong way ...
// ... can throw exceptions at runtime
public void Insert(int index, D item)
{
if (item is S)
{
this.source.Insert(index, (S)item);
}
else
{
throw new Exception("Invalid type exception");
}
}

包装中的 Insert 方法有一个问题。它将 D 当作参数,但是它必须将 D 插入到 IList<S> 中。由于 D 是 S 的基类型,不是所有的 D 都是 S,因此 Insert 操作可能会失败。此示例与数组的变化有相似之处。当将对象插入 object[] 时,将执行动态类型检查,因为 object[] 在运行时可能实际为 string[]。例如:

object[] objects = new string[10];
// no problem, adding a string to a string[]
objects[0] = "hello";
// runtime exception, adding an object to a string[]
objects[1] = new object();

在 IList<> 示例中,当实际类型在运行时与需要的类型不匹配时,可以仅仅引发 Insert 方法的包装。所以,您同样可以想象得到编译器将为程序员自动生成此包装。然而,有时候并不应该执行此策略。IndexOf 方法在集合中搜索所提供的项,如果找到该项,则返回该项在集合中的索引。然而,如果没有找到该项,IndexOf 方法将仅仅返回 -1,而并不引发。这种类型的包装不能由自动生成的包装提供。

到目前为止,我们描述了泛型变化问题的两种最简单的解决方法。然而,变化问题 可能变得要多复杂就有多复杂。例如,当您将 List<IEnumerable<int>>当作 List<IEnumerable<object>>,或将 List<IEnumerable<IEnumerable<int>>> 当作 List<IEnumerable<IEnumerable<object>>> 时。

当生成这些包 装以解决代码中的变化问题时,可能给代码带来巨大的系统开销。同时,它还会带来引用标识问题,因为每个包装的标识都与原始集合的标识不一样,从而会导致不 易察觉的 Bug。当使用泛型时,应选择类型实例化,以减少紧密关联的组件之间的不匹配问题。这可能要求在设计代码时做出一些妥协。与往常一样,设计程序时必须权衡 相互冲突的要求,在设计过程中应当考虑语言中类型系统具有的约束。

有的类型系统将泛型变化作为语言的首要任务。Eiffel 是其中一个主要示例。然而,将泛型变化作为类型系统的首要任务会明显增加 C# 的类型系统的复杂性,即使在不涉及变化的相对简单方案中也是如此。因此,C# 的设计人员觉得不包括变化才是 C# 的适当选择。

下面是上述示例的完整源代码。

using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
static class VarianceWorkaround
{
// Simple workaround for single method
// Variance in one direction only
public static void Add<S, D>(List<S> source, List<D> destination)
where S : D
{
foreach (S sourceElement in source)
{
destination.Add(sourceElement);
}
}
// Workaround for interface
// Variance in one direction only so type expressinos are natural
public static IEnumerable<D> Convert<S, D>(IEnumerable<S> source)
where S : D
{
return new EnumerableWrapper<S, D>(source);
}
private class EnumerableWrapper<S, D> : IEnumerable<D>
where S : D
{
public EnumerableWrapper(IEnumerable<S> source)
{
this.source = source;
}
public IEnumerator<D> GetEnumerator()
{
return new EnumeratorWrapper(this.source.GetEnumerator());
}
IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
private class EnumeratorWrapper : IEnumerator<D>
{
public EnumeratorWrapper(IEnumerator<S> source)
{
this.source = source;
}
private IEnumerator<S> source;
public D Current
{
get { return this.source.Current; }
}
public void Dispose()
{
this.source.Dispose();
}
object IEnumerator.Current
{
get { return this.source.Current; }
}
public bool MoveNext()
{
return this.source.MoveNext();
}
public void Reset()
{
this.source.Reset();
}
}
private IEnumerable<S> source;
}
// Workaround for interface
// Variance in both directions, causes issues
// similar to existing array variance
public static ICollection<D> Convert<S, D>(ICollection<S> source)
where S : D
{
return new CollectionWrapper<S, D>(source);
}
private class CollectionWrapper<S, D>
: EnumerableWrapper<S, D>, ICollection<D>
where S : D
{
public CollectionWrapper(ICollection<S> source)
: base(source)
{
}
// variance going the wrong way ... 
// ... can yield exceptions at runtime
public void Add(D item)
{
if (item is S)
{
this.source.Add((S)item);
}
else
{
throw new Exception(@"Type mismatch exception, due to type hole introduced by variance.");
}
}
public void Clear()
{
this.source.Clear();
}
// variance going the wrong way ... 
// ... but the semantics of the method yields reasonable semantics
public bool Contains(D item)
{
if (item is S)
{
return this.source.Contains((S)item);
}
else
{
return false;
}
}
// variance going the right way ... 
public void CopyTo(D[] array, int arrayIndex)
{
foreach (S src in this.source)
{
array[arrayIndex++] = src;
}
}
public int Count
{
get { return this.source.Count; }
}
public bool IsReadOnly
{
get { return this.source.IsReadOnly; }
}
// variance going the wrong way ... 
// ... but the semantics of the method yields reasonable  semantics
public bool Remove(D item)
{
if (item is S)
{
return this.source.Remove((S)item);
}
else
{
return false;
}
}
private ICollection<S> source;
}
// Workaround for interface
// Variance in both directions, causes issues similar to existing array variance
public static IList<D> Convert<S, D>(IList<S> source)
where S : D
{
return new ListWrapper<S, D>(source);
}
private class ListWrapper<S, D> : CollectionWrapper<S, D>, IList<D>
where S : D
{
public ListWrapper(IList<S> source) : base(source)
{
this.source = source;
}
public int IndexOf(D item)
{
if (item is S)
{
return this.source.IndexOf((S) item);
}
else
{
return -1;
}
}
// variance the wrong way ...
// ... can throw exceptions at runtime
public void Insert(int index, D item)
{
if (item is S)
{
this.source.Insert(index, (S)item);
}
else
{
throw new Exception("Invalid type exception");
}
}
public void RemoveAt(int index)
{
this.source.RemoveAt(index);
}
public D this[int index]
{
get
{
return this.source[index];
}
set
{
if (value is S)
this.source[index] = (S)value;
else
throw new Exception("Invalid type exception.");
}
}
private IList<S> source;
}
}
namespace GenericVariance
{
class Program
{
static void PrintObjects(IEnumerable<object> objects)
{
foreach (object o in objects)
{
Console.WriteLine(o);
}
}
static void AddToObjects(IList<object> objects)
{
// this will fail if the collection provided is a wrapped collection 
objects.Add(new object());
}
static void Main(string[] args)
{
List<int> ints = new List<int>();
ints.Add(1);
ints.Add(10);
ints.Add(42);
List<object> objects = new List<object>();
// doesnt compile ints is not a IEnumerable<object>
//objects.AddRange(ints); 
// does compile
VarianceWorkaround.Add<int, object>(ints, objects);
// would like to do this, but cant ...
// ... ints is not an IEnumerable<object>
//PrintObjects(ints);
PrintObjects(VarianceWorkaround.Convert<int, object>(ints));
AddToObjects(objects); // this works fine
AddToObjects(VarianceWorkaround.Convert<int, object>(ints));
}
static void ArrayExample()
{
object[] objects = new string[10];
// no problem, adding a string to a string[]
objects[0] = "hello";
// runtime exception, adding an object to a string[]
objects[1] = new object();
}
}
}

[C#]泛型与强制类型转换

mikel阅读(1174)

4. 泛型和强制类型转换

  4.1 C#编译器只允许将泛型参数隐式强制转换到Object或约束指定的类型

          interface ISomeInterface

      { ……}

     class BaseClass

      {……}

      class MyClass<T> where :BaseClass ,ISomeInterface

      {

        void SomeMethod(T t)

        {

            //类型安全的,编译时检查

            ISomeInterface obj1=t;

            BaseClass obj2=t;

            object obj3=t

        }

       }

   4.2 编译器允许你将泛型参数显示强制转换到其他任何接口,但不能将其转换到类

           interface ISomeInterface

       { ……}

     class SomeClass

       {……}

       class MyClass<T>

       { 软件开发网 www.mscto.com

         void SomeMethod(T t)

         {

            ISomeInterface obj1=(ISomeInterface)t;  //complies

            SomeClass obj2=(SomeClass)t;            //Does not complies

         }

        }

           但是,使用临时的 Object 变量,将泛型参数强制转换到其他任何类型

            class SomeClass

        {……}

       class MyClass2<T>

        {

            void SomeMethod(T t)

           {

软件开发网 www.mscto.com

               object temp = t;

                SomeClass obj = (SomeClass)temp;

            }

          }

     4.2 不用说强制转换时危险的,因为如果为取代泛型参数而使用的类型参数不是派生自你要显示强制转换到的类型,则可能引发异常。 软件开发网 www.mscto.com

        解决强制类型转换的方法:使用isas运算符

        public class MyClass3<T>

        {

             public void SomeMethod(T t)

             { 软件开发网 www.mscto.com

                   //如果泛型参数的类型是所查询的类型,则is运算符返回true

                   if (t is int) { }

                   if (t is LinkedList<int, string>) { }

软件开发网 www.mscto.com

                   string str = t as string; 软件开发网 www.mscto.com

                   if (str != null) { }

                   LinkedList<int, string> list = t as LinkedList<int, string>;

                   if (list != null) { }

              } 软件开发网 www.mscto.com

         }

[Chrome]Chrome源码刨析

mikel阅读(972)

【序】 

开源是口好东西,它让这个充斥着大量工业垃圾代码和教材玩具代码的行业,多了一些艺术气息和美的潜质。它使得每个人,无论你来自米国纽约还是中国铁岭,都有机会站在巨人的肩膀上,如果不能,至少也可以抱一把大腿。。。

现在我就是来抱大腿的,这条粗腿隶属于 Chrome(开源项目名称其实是Chromium,本来Chrome这个名字就够晦涩了,没想到它的本名还更上一层楼…),Google那充满狼子 野心的浏览器。每一个含着金勺子出生的人都免不了被仰慕并被唾骂,Chrome也不例外。关于Chrome的优劣好坏讨论的太多了,基本已经被嚼成甘蔗渣 了,没有人愿意再多张一口了。俗话说,内行看门道外行看热闹,大部分所谓的外行,是通过使用的真实感受来评定优劣的,这无疑是最好的方式。但偏偏还是有自 诩的内行,喜欢说内行话办外行事,一看到Chrome用到多进程就说垃圾废物肯定低能。拜托,大家都是搞技术的,你知道多进程的缺点,Google也知 道,他们不是政客,除了搞个噱头扯个蛋就一无所知了,人家也是有脸有皮的,写一坨屎一样的开源代码放出来遭世人耻笑难道会很开心?所谓技术的优劣,是不能 一概而论的,同样的技术在不同场合不同环境不同代码实现下,效果是有所不同的。既然Chrome用了很多看上去不是很美的技术,我们是不是也需要了解一下 它为什么要用,怎么用的,然后再开口说话?(恕不邀请,请自行对号入座…)。。。
人说是骡子是马拉出来遛遛,Google已经把 Chrome这匹驴子拉到了世人面前,大家可以随意的遛。我们一直自诩是搞科学的,就是在努力和所谓的艺术家拉开,人搞超女评委的,可以随意塞着屁眼用嘴 放屁,楞把李天王说是李天后,你也只能说他是艺术品位独特。你要搞科学就不行,说的不对,轻的叫无知,重的叫学术欺诈,结果一片惨淡。所以,既然代码都有 了,再说话,就只能当点心注点意了,先看,再说。。。
我已经开始遛Chrome这头驴了,确切一点, 是头壮硕的肥驴,项目总大小接近2G。这样的庞然大物要从头到脚每个毛孔的大量一遍,那估计不咽气也要吐血的,咱又不是做Code review,不需要如此拼命。每一个好的开源项目,都像是一个美女,这世界没有十全十美的美女,自然也不会有样样杰出的开源项目。每个美女都有那么一两 点让你最心动不已或者倍感神秘的,你会把大部分的注意力都放在上面细细品味,看开源,也是一样。Chrome对我来说,有吸引力的地方在于(排名分先 后…):

1. 它是如何利用多进程(其实也会有多线程一起)做并发的,又是如何解决多进程间的一些问题的,比如进程间通信,进程的开销;
2. 做为一个后来者,它的扩展能力如何,如何去权衡对原有插件的兼容,提供怎么样的一个插件模型;
3. 它的整体框架是怎样,有没有很NB的架构思想;
4. 它如何实现跨平台的UI控件系统;
5. 传说中的V8,为啥那么快。

但Chrome是一个跨平台的浏览器,其Linux和Mac版本正在开发过程中,所以我把所有的眼光都放在了windows版本中,所有的代码剖析都是基于windows版本的。话说,我本是浏览器新手、win api白痴以及并发处理的火星人,为了我的好奇投身到这个溜驴的行业中来,难免有学的不到位看的走眼的时候,各位看官手下超生,有错误请指正,实在看不下去,回家自己牵着遛吧。。。
扯淡实在是个体力活,所以后面我会少扯淡多说问题。。。
关于Chrome的源码下载和环境配置,大家看这里(windows版本),只想强调一点,一定要严格按照说明来配置环境,特别是vs2005的补丁和windows SDK的安装,否则肯定是编译不过的。。。
最后,写这部分唯一不是废话的内容,请记住以下这幅图,这是Chrome最精华的一个缩影,如果你还有空,一定要去这里进行阅读,其中重中之重是这一篇。。。
图1 Chrome的线程和进程模型

【一】 Chrome的多线程模型

0. Chrome的并发模型

如果你仔细看了前面的图,对Chrome的线程和进程框架应该有了个基本的了解。Chrome有一个主进程,称为Browser进程,它是老大,管理 Chrome大部分的日常事务;其次,会有很多Renderer进程,它们圈地而治,各管理一组站点的显示和通信(Chrome在宣传中一直宣称一个 tab对应一个进程,其实是很不确切的…),它们彼此互不搭理,只和老大说话,由老大负责权衡各方利益。它们和老大说话的渠道,称做 IPC(Inter-Process Communication),这是Google搭的一套进程间通信的机制,基本的实现后面自会分解。。。

Chrome的进程模型
Google在宣传的时候一直都说,Chrome是one tab one process的模式,其实,这只是为了宣传起来方便如是说而已,基本等同广告,实际疗效,还要从代码中来看。实际上,Chrome支持的进程模型远比宣传丰富,你可以参考一下
这里 ,简单的说,Chrome支持以下几种进程模型:

  1. Process-per-site-instance:就是你打开一个网站,然后从这个网站链开的一系列网站都属于一个进程。这是Chrome的默认模式。
  2. Process-per-site: 同域名范畴的网站放在一个进程,比如www.google.com和www.google.com/bookmarks就属于一个域名内(google有 自己的判定机制),不论有没有互相打开的关系,都算作是一个进程中。用命令行–process-per-site开启。
  3. Process-per-tab:这个简单,一个tab一个process,不论各个tab的站点有无联系,就和宣传的那样。用–process-per-tab开启。
  4. Single Process:这个很熟悉了吧,传统浏览器的模式,没有多进程只有多线程,用–single-process开启。

关于各种模式的优缺点,官方有官方的说法,大家自己也会有自己的评述。不论如何,至少可以说明,Google不是由于白痴而采取多进程的策略,而是实验出来的效果。。。
大家可以用Shift+Esc观察各模式下进程状况,至少我是观察失败了(每种都和默认的一样…),原因待跟踪。。。

不论是Browser进程还是Renderer 进程,都不只是光杆司令,它们都有一系列的线程为自己打理各种业务。对于Renderer进程,它们通常有两个线程,一个是Main thread,它负责与老大进行联系,有一些幕后黑手的意思;另一个是Render thread,它们负责页面的渲染和交互,一看就知道是这个帮派的门脸级人物。相比之下,Browser进程既然是老大,小弟自然要多一些,除了大脑般的 Main thread,和负责与各Renderer帮派通信的IO thread,其实还包括负责管文件的file thread,负责管数据库的db thread等等(一个更详细的列表,参见这里),它们各尽其责,齐心协力为老大打拼。它们和各Renderer进程的之间的关系不一样,同一个进程内的线程,往往需要很多的协同工作,这一坨线程间的并发管理,是Chrome最出彩的地方之一了。。。

闲话并发
单进程单线程的编程是最惬意的事情,所看即所得,一维的思考即可。但程序员的世界总是没有那么美好,在很多的场合,我们都需要有多线程、多进程、多机器携起手来一齐上阵共同完成某项任务,统称:并发(非官方版定义…)。在我看来,需要并发的场合主要是要两类:

  1. 为了更好的用户体验。 有的事情处理起来太慢,比如数据库读写、远程通信、复杂计算等等,如果在一个线程一个进程里面来做,往往会影响用户感受,因此需要另开一个线程或进程转到 后台进行处理。它之所以能够生效,仰仗的是单CPU的分时机制,或者是多CPU协同工作。在单CPU的条件下,两个任务分成两拨完成的总时间,是大于两个 任务轮流完成的,但是由于彼此交错,更人的感觉更为的自然一些。
  2. 为了加速完成某项工作。 大名鼎鼎的Map/Reduce,做的就是这样的事情,它将一个大的任务,拆分成若干个小的任务,分配个若干个进程去完成,各自收工后,在汇集在一起,更 快的得到最后的结果。为了达到这个目的,只有在多CPU的情形下才有可能,在单CPU的场合(单机单CPU…),是无法实现的。

在第二种场合下,我们会自然而然的关注数据的分离,从而很好的利用上多CPU的能力;而在第一种场合,我们习惯了单CPU的模式,往往不注重数据与行为的对应关系,导致在多CPU的场景下,性能不升反降。。。

1. Chrome的线程模型

仔细回忆一下我们大部分时候是怎么来用线程的, 在我足够贫瘠的多线程经历中,往往都是这样用的:起一个线程,传入一个特定的入口函数,看一下这个函数是否是有副作用的(Side Effect),如果有,并且还会涉及到多线程的数据访问,仔细排查,在可疑地点上锁伺候。。。
Chrome的线程模型走的是另一个路子,即,极力规避锁的存在。 换更精确的描述方式来说,Chrome的线程模型,将锁限制了极小的范围内(仅仅在将Task放入消息队列的时候才存在…),并且使得上层完全不需要 关心锁的问题(当然,前提是遵循它的编程模型,将函数用Task封装并发送到合适的线程去执行…),大大简化了开发的逻辑。。。
不过,从实现来说,Chrome的线程模型并没有什么神秘的地方(美女嘛,都是穿衣服比不穿衣服更有盼头…),它用到了消息循环的手段。每一个Chrome的线程,入口函数都差不多,都是启动一个消息循环(参见MessagePump类),等待并执行任务。而其中,唯一的差别在于,根据线程处理事务类别的不同,所起的消息循环有所不同。比如处理进程间通信的线程(注意,在Chrome中,这类线程都叫做IO线程,估计是当初设计的时候谁的脑门子拍错了…)启用的是MessagePumpForIO类,处理UI的线程用的是MessagePumpForUI类,一般的线程用到的是MessagePumpDefault类 (只讨论windows, windows, windows…)。不同的消息循环类,主要差异有两个,一是消息循环中需要处理什么样的消息和任务,第二个是循环流程(比如是死循环还是阻塞在某信 号量上…)。下图是一个完整版的Chrome消息循环图,包含处理Windows的消息,处理各种Task(Task是什么,稍后揭晓,敬请期 待…),处理各个信号量观察者(Watcher),然后阻塞在某个信号量上等待唤醒。。。
图2 Chrome的消息循环

当然,不是每一个消息循环类都需要跑那么一大圈的,有些线程,它不会涉及到那么多的事情和逻辑,白白浪费体力和时间,实在是不可饶恕的。因此,在实现中,不同的MessagePump类,实现是有所不同的,详见下表:

  MessagePumpDefault MessagePumpForIO MessagePumpForUI
是否需要处理系统消息
是否需要处理Task
是否需要处理Watcher
是否阻塞在信号量上

2. Chrome中的Task

从上面的表不难看出,不论是哪一种消息循环,必须处理的,就是Task(暂且遗忘掉系统消息的处理和Watcher,以后,我们会缅怀它们的…)。刨去其它东西的干扰,只留下Task的话,我们可以这样认为:Chrome中的线程从实现层面来看没有任何区别,它的区别只存在于职责层面,不同职责的线程,会处理不同的Task。最后,在铺天盖地西红柿来临之前,我说一下啥是Task。。。
简单的看,Task就是一个类,一个包含了 void Run()抽象方法的类(参见Task类…)。一个真实的任务,可以派生Task类,并实现其Run方法。每个MessagePump类中,会有一个 MessagePump::Delegate的类的对象(MessagePump::Delegate的一个实现,请参见MessageLoop 类…),在这个对象中,会维护若干个Task的队列。当你期望,你的一个逻辑在某个线程内执行的时候,你可以派生一个Task,把你的逻辑封装在 Run方法中,然后实例一个对象,调用期望线程中的PostTask方法,将该Task对象放入到其Task队列中去,等待执行。我知道很多人已经抄起了 板砖,因为这种手法实在是太常见了,就不是一个简单的依赖倒置,在线程池,Undo\Redo等模块的实现中,用的太多了。。。
但,我想说的是,虽说谁家过年都是吃顿饺子,这饺子好不好吃还是得看手艺,不能一概而论。在Chrome中,线程模型是统一且唯一的,这就相当于有了一套标准,它需要满足在各个线程上执行的几十上百种任务的需求,因此,必须在灵活行和易用性上有良好的表现,这就是设计标准的难度。为了满足这些需求,Chrome在底层库上做了足够的功夫:
  1. 它提供了一大套的模板封装(参见task.h),可以将Task摆脱继承结构、函数名、函数参数等限制(就是基于模板的伪function实现,想要更深入了解,建议直接看鼻祖《Modern C++》和它的Loki库…);
  2. 同时派生出CancelableTask、ReleaseTask、DeleteTask等子类,提供更为良好的默认实现;
  3. 在消息循环中,按逻辑的不同,将Task又分成即时处理的Task、延时处理的Task、Idle时处理的Task,满足不同场景的需求;
  4. Task派生自tracked_objects::Tracked,Tracked是为了实现多线程环境下的日志记录、统计等功能,使得Task天生就有良好的可调试性和可统计性;
这一套七荤八素的都搭建完,这才算是一个完整的Task模型,由此可知,这饺子,做的还是很费功夫的。。。

3. Chrome的多线程模型

工欲善其事,必先利其器。Chrome之所以费了老鼻子劲去磨底层框架这把刀,就是为了面对多线程这坨怪兽的时候杀的更顺畅一些。在Chrome的多线程模型下,加锁这个事情只发生在将Task放入某线程的任务队列中,其他对任何数据的操作都不需要加锁。当然,天下没有免费的午餐,为了合理传递Task,你需要了解每一个数据对象所管辖的线程,不过这个事情,与纷繁的加锁相比,真是小儿科了不知道多少倍。。。
图3 Task的执行模型
如果你熟悉设计模式,你会发现这是一个Command模式, 将创建于执行的环境相分离,在一个线程中创建行为,在另一个线程中执行行为。Command模式的优点在于,将实现操作与构造操作解耦,这就避免了锁的问 题,使得多线程与单线程编程模型统一起来,其次,Command还有一个优点,就是有利于命令的组合和扩展,在Chrome中,它有效统一了同步和异步处理的逻辑。。。

Command模式
Command 模式,是一种看上去很酷的模式,传统的面向对象编程,我们封装的往往都是数据,在Command模式下,我们希望封装的是行为。这件事在函数式编程中很正 常,封装一个函数作为参数,传来传去,稀疏平常的事儿;但在面向对象的编程中,我们需要通过继承、模板、函数指针等手法,才能将其实现。。。
应用Command模式,我们是期望这个行为能到一个不同于它出生的环境中去执行,简而言之,这是一种想生不想养的行为。我们做Undo/Redo的时 候,会把在任一一个环境中创建的Command,放到一个队列环境中去,供统一的调度;在Chrome中,也是如此,我们在一个线程环境中创建了 Task,却把它放到别的线程中去执行,这种寄居蟹似的生活方式,在很多场合都是有用武之地的。。。

在一般的多线程模型中,我们需要分清楚啥是同步 啥是异步,在同步模式下,一切看上去和单线程没啥区别,但同时也丧失了多线程的优势(沦落成为多线程串行…)。而如果采用异步的模式,那写起来就麻烦 多了,你需要注册回调,小心管理对象的生命周期,程序写出来是嗷嗷恶心。在Chrome的多线程模型下,同步和异步的编程模型区别就不复存在了,如果是这 样一个场景:A线程需要B线程做一些事情,然后回到A线程继续做一些事情;在Chrome下你可以这样来做:生成一个Task,放到B线程的队列中,在该 Task的Run方法最后,会生成另一个Task,这个Task会放回到A的线程队列,由A来执行。如此一来,同步异步,天下一统,都是Task传来传 去,想不会,都难了。。。
图4 Chrome的一种异步执行的解决方案

4. Chrome多线程模型的优缺点

一直在说Chrome在规避锁的问题,那到底锁 是哪里不好,犯了何等滔天罪责,落得如此人见人嫌恨不得先杀而后快的境地。《代码之美》的第二十四章“美丽的并发”中,Haskell设计人之一的 Simon Peyton Jones总结了一下用锁的困难之处,我罚抄一遍,如下:
  1. 锁少加了,导致两个线程同时修改一个变量;
  2. 锁多加了,轻则妨碍并发,重则导致死锁;
  3. 锁加错了,由于锁和需要锁的数据之间的联系,只存在于程序员的大脑中,这种事情太容易发生了;
  4. 加锁的顺序错了,维护锁的顺序是一件困难而又容易出错的问题;
  5. 错误恢复;
  6. 忘记唤醒和错误的重试;
  7. 而最根本的缺陷,是锁和条件变量不支持模块化的编程。比如一个转账业务中,A账户扣了100元钱,B账户增加了100元,即使这两个动作单独用锁保护维持其正确性,你也不能将两个操作简单的串在一起完成一个转账操作,你必须让它们的锁都暴露出来,重新设计一番。好好的两个函数,愣是不能组在一起用,这就是锁的最大悲哀;
通过这些缺点的描述,也就可以明白Chrome多线程模型的优点。它解决了锁的最根本缺陷,即,支持模块化的编程,你只需要维护对象和线程之间的职能关系即可,这个摊子,比之锁的那个烂摊子,要简化了太多。对于程序员来说,负担一瞬间从泰山降成了鸿毛。。。
而Chrome多线程模型的一个主要难点,在于线程与数据关系的设计上,你需要良好的划分各个线程的职责,如果有一个线程所管辖的数据,几乎占据了大半部分的Task,那么它就会从多线程沦为单线程,Task队列的锁也将成为一个大大的瓶颈。。。

设计者的职责
一 个底层结构设计是否成功,这个设计者是否称职,我一直觉得是有一个很简单的衡量标准的。你不需要看这个设计人用了多少NB的技术,你只需要关心,他的设 计,是否给其他开发人员带来了困难。一个NB的设计,是将所有困难都集中在底层搞定,把其他开发人员换成白痴都可以工作的那种;一个SB的设计,是自己弄 了半天,只是为了给其他开发人员一个长达250条的注意事项,然后很NB的说,你们按照这个手册去开发,就不会有问题了。。。

从根本上来说,Chrome的线程模型解决的是 并发中的用户体验问题而不是联合工作的问题(参见我前面喷的“闲话并发”),它不是和Map/Reduce那样将关注点放在数据和执行步骤的拆分上,而是 放在线程和数据的对应关系上,这是和浏览器的工作环境相匹配的。设计总是和所处的环境相互依赖的,毕竟,在客户端,不会和服务器一样,存在超规模的并发处理任务,而只是需要尽可能的改善用户体验,从这个角度来说,Chrome的多线程模型,至少看上去很美。。。

[Django]翻译www.djangobook.com之第二章:Django快速上手

mikel阅读(894)

The Django Book 第2章:Django快速上手
revised by xin_wang
谢天谢地,安装Django非常容易。因为Django可以运行在任何可以运行Python的环境中,所以可以以多种方式进行配置。
在本章我们将尝试覆盖几种常见的Django安装场景。
安装Python
Django是以100%纯Python代码写就,所以你需要安装Python,Django要求安装Python2.3或更高版本。
如果你使用Linux或者MacOSX,你可能已经安装了Python
在命令行或者终端下输入“python”,如果出现类似如下提示,表示Python已经安装好了:
Python 2.4.1 (#2, Mar 31 2005, 00:05:10)
[GCC 3.3 20030304 (Apple Computer, Inc. build 1666)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>>
否则,出现错误提示“command not found”
你可以到http://www.python.org/download/下载Python安装
安装Django
安装官方发布版本的Django
http://www.djangoproject.com/download/下载tarball的Django-*.tar.gz

Java代码 复制代码
  1. tar xzvf Django-*.tar.gz  
  2. cd Django-*  
  3. sudo python setup.py install  

Windows下安装则是直接解压Django-*.tar.gz并运行python setup.py install
安装完以后,在Python交互环境下应该可以import django模块

Java代码 复制代码
  1. >>> import django  
  2. >>> django.VERSION  
  3.  (10'official')  

Python交互环境是一个命令行程序,在命令行下运行“python”即可进入交互环境
在这本书里,我们将会演示一些Python代码例子,这些例子看起来像是在交互环境里面输入的。
Python交互环境的提示符是三个大于号(>>>)
从Subversion安装Django
如果你想安装Django最新代码或者你想向Django贡献代码,你应该从Django的Subversion repository安装
Subversion是一个与CVS类似的开源版本控制系统,Django团队使用它来管理Django代码的变化。
你可以随时使用Subversion客户端获取最新的Django源代码,或者更新你本机Subversion工作拷贝"local checkout"中的
Django代码来获得Django开发人员所作的最新修改和增强。
最新的Django开发代码称为“the trunk”
得到最新的Django trunk:
1,确认你安装了Subversion客户端,下载地址为http://subversion.tigris.org
Subverion的文档http://svnbook.redbean.com
2,运行如下命令得到trunk“svn co http://code.djangoproject.com/svn/django/trunk django_src”
3,符号链接django_src/django来让django在你的Python site-packages目录下,或者更新PYTHONPATH指定它
从Subversion安装不需要运行“python setup.py install”
Django trunk经常更新bug fixs和增加feature,你可能要频繁更新它
在django_src目录下运行“svn update”即可更新代码
建立数据库
Django仅有的先决条件就是安装Python,但是本书关注Django引以为傲的众多优点之一,开发支持数据库的Web站点
所以你需要安装一个数据库服务器来存储数据
如果你只是想浅尝辄止,可以跳过这一步直接开始一个项目,可是请相信我们:你最终还是会装一个数据库,因为本书的
所有例子都假设你已经拥有一个数据库
Django1.0支持5个数据库引擎:
PostgreSQL(http://www.postgresql.org/)
SQLite 3(http://www.sqlite.org/)
MySQL(http://www.mysql.com/)
Microsoft SQL Server(http://www.microsoft.com/sql/)
Oracle(http://www.oracle.com/database/)
我们自己特别喜欢PostgreSQL,所以我们最先提到它
尽管如此,所有的这些数据库都在Django上工作得都很好
SQLite也值得特别注意,它是一个非常简单的数据库引擎,不需要任何服务器安装和配置
如果你只是想玩玩Django的话,SQLite是最容易安装的
使用PostgrSQL来和Django工作
如果你用PostgreSQL,你需要psycopg包,从http://initd.org/projects/psycopg1可以得到
确认你使用版本1而不是版本2,2还是beta版
如果你在Windows上使用PostgreSQL,可以从如下地址下载已经编译好的二进制psycopg
http://stickpeople.com/projects/python/win-psycopg/
使用SQLite 3来和Django工作
你需要SQLite 3而不是SQLite 2,从http://initd.org/tracker/pysqlite下载pysqlite
确认下载pysqlite的版本为2.0.3及以上
使用MySQL来和Django工作
Django需要MySQL版本4.0及以上,3.x版本不支持事务、嵌套存储过程以及其它标准SQL语句
你也需要MySQLdb包,下载地址http://sourceforge.net/projects/mysql-python
使用MSSQL来和Django工作
使用Oracle来和Django工作
不使用数据库来和Django工作
就像刚刚提到的,Django实际上不需要数据库
如果你仅仅希望Django来提供动态网页而不触及数据库也是可以的
和Django绑定的一些额外的工具需要数据库,如果你选择不使用数据库,你会错失那些特性
开始一个项目
如果这是你第一次使用Django,你必须注意一些初始化过程
运行“django-admin.py startproject mysite”将会在你的当前目录下创建一个mysite目录
注意,如果你使用setup.py安装Django,django-admin.py应该在你的PATH系统变量下
如果不在PATH里面,你可以从site-packages/django/bin找到它
考虑符号链接它到你的PATH里面,例如/usr/local/bin
一个项目就是一个Django实例的设置的集合,包括数据库配置、Django的专有设置以及应用程序专有设置
让我们看看startproject创建了什么:
/mysite/
__init__.py
manage.py
settings.py
urls.py
这些文件的说明如下:
manage.py
一个命令行工具,可以让你以多种方式与Django项目交互
setting.py
Django项目的配置
urls.py
Django项目的URL定义
如果你使用PHP,你可能习惯于将代码放在Web服务器的document root下,如/var/www
使用Django的话不要这样做,将Python代码放在document root下不是一个好主意
因为这样的话人们可能从Web看到你的代码,这并不安全
把你的代码放在document root以外的目录,如/home/mycode
开发用服务器
切换到mysite目录,运行“python manage.py runserver”,你将看到如下信息
Validating models…
0 errors found.
Django version 1.0, using settings 'mysite.settings'
Development server is running at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
这样你就启动了Django开发用服务器,这是一个包含在Django中的开发阶段使用的轻量级Web服务器
我们在Django中包含了这个服务器是为了快速开发,这样在产品投入应用之前,就可以不用处理生产环境中
web server的配置工作了。
这个服务器查看你的代码,如果有改动,它自动reload,让你不需重启快速修改你的项目
虽然这个开发用服务器对于开发来说简直棒透了,还是请克制一下把它用在任何形式的生产环境中的冲动。
这个服务器一次只能可靠地处理一个请求,而且根本没有经过任何安全性的检验
如果你的站点需要上线,请参考第21章的关于部署Django程序的介绍
默认情况下runserver命令启动服务器的端口为8000,只监听本地连接
如果你希望改变端口,增加一个命令行参数即可
python manage.py runserver 8080
你也可以改变服务器监听的IP地址,当你同其它开发者分享一个开发站点时很有用
python manage.py runserver 0.0.0.0:8080
上面的命令使得Django监听任何网络接口,这样的话就允许其它计算机连接该服务器
试着访问http://127.0.0.1:8000/,你将会看到“Welcome to Django”的页面
下一步是什么?
我们已经安装好一切的东西并且让服务器运行了,让我们写一点基本代码来展示怎样使用Django提供动态页面

[Python]Python的web框架汇总

mikel阅读(888)

1.Snakelets
Snakelets 是一个 Python 编写的web server,从我了解的j几种 web framework 来讲,我认为snakelet功能似乎更强,它是一个象servlet的一个东西,许多东西已经做好了,象模板,用户认证(提供多种方式)等,看了那个Frog,我还是很喜欢他的,小研究了一下他的代码,发现实在有点复杂,不容易明白,目前没有一个合适的入门教材,而且本身有些复杂,所以处于放弃状态~
2.Django
Django是一个高级 Python web framework,它鼓励快速开发和干净的、MVC设计。它包括一个模板系统,对象相关的映射和用于动态创建管理界面的框架。
他没发布之前就已经吸引了不少人了, 比以前的,更加注重整体设计
特性介绍:
对象相关的映射
完全在Python中定义你的数据模型。你可以免费得到一个丰富的,动态访问数据库的API--但如果需要你仍然可以写SQL语句。
URL 分发
URL的设计漂亮,cruft-free,没有框架的特定限定。象你喜欢的一样灵活。
模版系统
使用DjanGo强大而可扩展的模板语言来分隔设计、内容和Python代码。
Cache系统
可以挂在内存缓冲或其它的框架实现超级缓冲 -- 实现你所需要的粒度。
自动化的管理界面
不需要你花大量的工作来创建人员管理和更新内容的接界。DjanGo可以自动完成。
支持多种数据库
已经支持PostgreSQL, MySql, Sqlite3
我倾向使用他,但是很遗憾没调试成功~ [redface]
3.Karrigell
作 为简单web开发解决, Karrigell已经包含了web服务,Python 脚本引擎,和 100% 纯Python的数据库: KirbyBase ; 你所要关心的就是创建自个儿的动态web 应用. 这个是我目前主要研究的对象,因为DjanGo没有运行成功,而据介绍Karrigell也是一个非常优秀的 web framework 框架.现在环境设置成功了,如果可以,就可以开始入门学习了~
karrigell是利用mod_python与 apache集成,不需要再运行自已的server,Karrigell不需要挂接处理。写一个.py, .hip, .pih,.ks都是可以的。.py就是普通的python程序,print的结果会作为结果输出。.hip就是Html in Python ,与.py有些象,但在 Python 顶层可以直接以字符串形式写html的代码。.pih就是Python in Html,与其它的 Python Html 模板很象,就是在 Html 模板中嵌入 Python 程序。使用<% %>来包括。.ks就是Karrigell Service,它与 CherryPy 中的方法发布有些象,但不用设置哪个方法需要发布,也不是类的写法,只是函数的写法。
4.Quixote
快速进入 无畏的骑士! 豆瓣 的主要动力系统!正因为这个,我对他的关注也多了很多~
这个框架目前国内使用的人不多,但是豆瓣正是使用了他而成功的,目前这个框架我还没开始尝试
下面有一些资料可以帮你了解他~
http://quixote.ca/
http://www.mems-exchange.org/software/quixote/apps.html
其实Python的Web 开发框架还有很多,象TurboGears ,但我目前接触的比较多的就这几个,其他的在啄木鸟社区还有很多介绍,感兴趣的,可以自己去看看,也欢迎大家能推荐一些比较好用的Web 开发框架介绍,和使用经验,共同体验python的开发乐趣~