页面

2010年11月20日星期六

MMORPG通用服务端引擎分析方式

转自:http://www.cnblogs.com/Alexander-Lee/archive/2010/11/20/ViewOfHightPerformanceMMORPGGameServer.html

一般来说,当然是想一个游戏装的用户越多越好,当然这里有很多现实上的制约,第一是运营上,游戏里总是老玩家等级更高、实力更强,由于游戏的竞争性,玩家都喜欢进新服,所以一组服务器总是在开服的时候开始在线人数持续攀升,然后在某个点后就会下降并趋于稳定。其二是因为游戏中的场景不是无限大的,有固有的玩家密度限制,如果一个游戏屏幕上到处都塞满人,估计你也不会觉得好玩。并且根据这两个特点就决定了,MMORPG的服务引擎需要有高性能,这样才能在开服的时候承载尽可能多的用户进入,并且要具备高度的可伸缩性,在开服用户在线高峰的时候可以用比较多的服务器资源来拉动用户,在平稳运行后能够省出多余的服务器资源来挪给其他的服务器组。
从最简单的来说,MMORPG游戏基本上就是经典的C-S结构的系统,所以最简单的结构就是
Server  
    |  
    |

 Client

这个时候Server端什么都要处理,就是忒累点,所以承载能力也就不用指望了,扩展能力就更不用想了,不过胜在简单,如果好好设计性能还是有保障的。有个开源的C#开发的UO的服务引擎实现大家可以借鉴一下,http://www.runuo.com/。其实从本质上来说MMORPG的服务端和企业应用没有差别,所以我们解决问题的方式也是很相似的,如果性能有问题,一台服务器无法解决问题,就用两台,属于叫分而治之的策略,所以要提高性能,我们需要从系统的最慢的地方开始。如果有点经验的开发人员都知道,系统中最慢的就是数据库了。所以要提高系统的响应,我们一般是在用户的角色登录的时候直接将角色的数据读进内存来处理,但是内存的数据不怎么保险,万一服务器当掉或者掉电了怎么办呢,这个问题就需要定时将用户的数据变更发给数据库了,这样就不存在读写数据库的延迟了,当然掉电的时候在上一次保存后的数据还是会掉,这个时候就叫服务器回档,这种小几率事件一般我们不用特殊处理,一般游戏偶尔出现故障回档的话基本都是对在线的用户赔点经验装备了事。以后架构还有可能扩张,而为了让你不必将SQL写得满世界都是,我们将数据库操作抽象成数据库服务,为了多台服务器都可以一视同仁的使用,也也可以单独用一台服务器来作为数据库服务的主机,如下图:

DB-Service
       |
  Server  
       |
    CLient  

 

这张图看着很眼熟吧,恩,啥三层架构不就是这么画的嘛。� 这个时候系统的压力就不在数据存储上了,于是压力到了游戏的逻辑上,现在游戏既要同时处理大量的并发网络请求,且还要对游戏的逻辑进行运算,一边是高IO应用,一边是高CPU运算,都放在一块那就是一半火焰一半海水,不是烧死就是淹死了。高网络IO并不需要很强的CPU运算性能,比如路由器,一台城域网的核心路由器负担了整个城市的出口网络路由,IO高得吓人,路由器其实也就是一台特殊的电脑,但是这台核心路由器的CPU其实并不比我们的家用PC的CPU高,甚至有可能低一点。但是游戏的逻辑运算对CPU的消耗就是实打实的消耗了,假设游戏有1000个玩家在线,这个时候每处理一个事件需要1ms,那么假设每个玩家每秒有4个事件需要处理,那么1000个玩家就把一颗4核CPU或者2颗双核CPU的计算能力耗尽了,这里还是假设的理想情况,如果再加上NPC,怪物,物品之类的要处理,那就需要非常多的CPU资源,如果所有CPU资源都给了逻辑运算,网络消息处理所需的CPU能力就不足了,虽然消耗低,但是总是消耗的,所以我们继续采取分而治之的办法来处理,我们把前端服务器和逻辑服务器分开,前端服务器用来处理大量的用户链接和消息分发,而逻辑服务器用来处理游戏逻辑。由于游戏逻辑更消耗CPU,所以一个前端服务器可以带N台逻辑服务器,所以结构改成了下图:  

 

Logic-Service   Logic-Service    DB-Service
         |                     |                       |
         -------------------------------------
                               |
                       Front Server
                               |
                            Client                   

 我们可以继续将游戏逻辑进行分类,由于MMORPG的每一个玩家从经入游戏开始就是处于一个个的场景当中的,所以逻辑服务器也可以叫场景服务器(地图服务器),有的游戏即使没有场景切换,其实也是分了很多场景的,只是采用了无缝拼接的技术让你觉得是没有分开的。玩家的逻辑就可以分为连续事件逻辑和瞬时逻辑。连续事件逻辑是在场景中需要和其他用户发生反映的事件,也可以称之为场景事件,比如我攻击了一个怪,这一个事件需要通知场景里所有的玩家知道,并且会影响怪接下来的行动。所谓的瞬时事件,就是只会影响玩家自身的状态且不需要通知其他玩家或者说是对场景产生影响的(当然如果对场景产生了影响势必需要通知场景内其他玩家)。有的事件甚至会跨场景通知系统内所有用户(比如某玩家击杀了某著名BOSS,或者通知师父自己的徒弟在某处遭到了攻击[假如要实现师徒系统的话])。玩家大部分的逻辑都是在场景内完成的,所以场景逻辑的实现非常的重要。在这个部分的运算涉及到多个对象间的互动,如果想用多线程来提高并行度来提高性能其实反而会适得其反,因为要保证计算的数据安全避免脏读,在多线程的环境下就需要处理大量的锁,相信在游戏的业务逻辑里还需要处理锁,防止死锁这里的处理会宁所有的程序员抓狂,对于这种高CPU运算的场景来说,大量的线程也会将宝贵的CPU时间浪费不少在线程切换上,所以一般来说游戏的逻辑服务器都是单进程单线程的结构,通过一个大循环来驱动整个事件逻辑。那么你可能会问,如果有单进程单线程岂不是只能利用一颗CPU内核了么?当然一个游戏也不可能只有一个场景嘛,我们可以在一台服务器上跑N个场景服务,处理N个场景的逻辑(根据经验来说,N=CPU内核数量性能最好)。所以你可以看到为啥上图我不写Logic Server而是写的Logic Service了。
当玩家连接上Front Server后怎么知道要把数据发到那一个Logic Service呢?这里就需要场景管理服务了,根据我的想法,我想在场景管理服务里提供一个用户代理,用户代理知道用户在那个场景中,代理了用户登录场景,离开场景的行为,以及帮助用户将数据转发到正确的场景服务上,所以结构图继续进化成下图:


 Logic-Service   Logic-Service    DB-Service
           |                     |                      |
           ------------------------------------
                                 |
                       Scene Manager
                                  |

                          Front Server
                                  |
                               Client
由于Front Server的数据都由场景管理服务器转发到场景上,所以我们在前端可以部署多个Front Server,因为一个Front Server只有100M的带宽,当Front Server性能不足或者带宽不足的时候我们可以通过两个来搞定,而Scene Manager只通过用户代理来做包转发,所以承载能力相当的高。再次增强后系统如下图:
 Logic-Service   Logic-Service    DB-Service
          |                      |                     |
          ------------------------------------
                                 |
                      Scene Manager
                                 |
                        ----------------
                        |                   |
                Front Server   Front Server
                        |                   |
                       Client         Client

考虑到Front Server有可能会存在CPU剩余的情况,所以也可以将一部分瞬时事件交给Front Server来处理,当然有一个公共的很耗时的瞬时逻辑需要被剥离出来,那就是登录的逻辑,登录的逻辑每一组服务器都一样,所以我们可以将N组服务器的登录交给一个统一的登录服务器来处理,所以我们再次进化

 Logic-Service   Logic-Service    DB-Service
           |                     |                     |
           -----------------------------------
                                 |
                        Scene Manager
                                 |
               ------------------------------------- 
              |                       |                      |
          Front Server   Front Server     Login Server
              |                      |
             Client             Client                

 

 现在看起来大体上已经有点模样了,但是其实还可以根据不同的需求做一些细节上的调整,比如怪物的AI运算,如果仅仅是很简单的逻辑运算,其实就可以直接在场景服务器的逻辑中处理了(其实有点像把怪物当作了场景的一部分)。如果需要很复杂的AI,就需要将怪物的AI拿到单独的进程里运算了,其实就是把怪物当成一个特殊的玩家来对待,这种模式比较特殊,由于比较耗资源,一般都对大BOSS采用这种方式。

2010年11月14日星期日

关于js中的webWorker(另一种多线程)


//worker.js
onmessage = function (evt){
  var d = evt.data;//通过evt.data获得发送来的数据
  postMessage(d+"双核时代来啦");//再发送回去,礼尚往来
}
//main thread
var w = new Worker("worker.js");
w.postMessage("javascript");
w.onmessage = function(evt){
  alert(evt.data);//获取新线程的js发送来的数据
}

2010年11月2日星期二

flash中的安全沙箱

  前几天看了下《深入java虚拟机》中的安全性一章,借次再回头来分析温习一下flash中的安全模型
  这里主要记录一下单纯网络沙箱中的安全。
  在flash中有一个安全域的概念,每一个加载域中的内容都被加载者加载到一个单独的安全域中,比如对于A.swf,加载本域的B.swf则直接加载到A.swf所在的安全域中,加载exmple2.com中的c.swf,则会把c.swf放到一个单独的安全域中。
  每个安全域中可以定义多个应用程序域,应用程序域只是用来保存独立的引用。
  按照java中的安全模型,安全水箱同 类加载器----……-----安全管理器组成,在一个虚拟机实例启动时会同时实例一个Sys.setSecurityManager(securityManager);在每一个执行线程中,对于特殊的操作,如文件操作等需要安全验证的操作,虚拟机都会调用securityManager.checkPermission(java.security.permission)---->AccessController.checkPermission(perm)来执行验证,验证不通过则抛出异常,其中perm为根据策略文件生成的Permission子类实例
  同样,在flash中应该也采取类似的验证方式,不同的是flash中把外部资料分为了两类:
        加载内容:为可视化媒体、音频、视频等媒体资源;
        提取或访问数据:数据为媒体资源的像素或者音频波形数据,或者其它文本数据
  在加载内容和访问数据两方面采取的安全策略不尽相同,
    对于加载内容方面的策略只需要遵从那些本地沙箱、本地可信任沙箱、网络沙箱等规则;
    对于数据方面的策略则要更加严格一些,需要使用策略文件或者Security.allowDomin()
  
未完待续

2010年10月27日星期三

记录Adobe Flash Platform一些技术

今天看到一个叫做Flash Media Gateway的技术,主要做的工作如下图:Flash Media Gateway flowchart
应该是建立从PC到移动设备间的通信吧!相当于全互联网部署应用,资料地址:http://labs.adobe.com/technologies/flashmedia_gateway/

2010年10月21日星期四

自己配置flash tracer

    在firefox下有个flashTracer插件,可以查看debug版下flash程序里的trace信息
    但如果没有firefox怎么办?这时候就得学会自己配置一下来查看trace信息了,它插件只是用adobe做出来的debug外置接口做了方便一点的输出台而已
    原理上应该是flash debug会在flash播放器里内置一个程序,这个程序可以跟踪AVM2中的执行过程,并能通过加载C:\Documents and Settings\username\mm.cfg文件读取一些配置信息,然后根据配置信息在跟踪代码执行过程当中把一些需要的信息写入到C:\Documents and Settings\username\Application Data\Macromedia\Flash Player\Logs\flashlog.txt文件当中去,所以要配置自己的trace控制台,只需要准备这个mm.cfg文件并写好里面的配置参数就好了,如果想让查看log信息方便点可以自己写个本地程序来读取flashlog.txt文件内容显示出来,当然肯定已经有第三方写出来了这样的工具了,Vizzy就是一个,项目 地址http://code.google.com/p/flash-tracer
    另外还要熟悉一些配置参数
        
Property Description

ErrorReportingEnable

Enables the logging of error messages.

Set the ErrorReportingEnable property to 1 to enable the debugger version of Flash Player to write error messages to the log file.

To disable logging of error messages, set theErrorReportingEnable property to 0.

The default value is 0.

MaxWarnings

Sets the number of warnings to log before stopping.

The default value of the MaxWarnings property is 100. After 100 messages, the debugger version of Flash Player writes a message to the file stating that further error messages will be suppressed.

Set the MaxWarnings property to override the default message limit. For example, you can set it to 500 to capture 500 error messages.

Set the MaxWarnings property to 0 to remove the limit so that all error messages are recorded.

TraceOutputFileEnable

Enables trace logging.

Set TraceOutputFileEnable to 1 to enable the debugger version of Flash Player to write trace messages to the log file.

Disable trace logging by setting the TraceOutputFileEnableproperty to 0.

The default value is 0.

TraceOutputFileName

Sets the location of the log file. By default, the debugger version of Flash Player writes error messages to a file named flashlog.txt.

Set TraceOutputFileName to override the default name and location of the log file by specifying a new location and name in the following form:

TraceOutputFileName=<fully qualified path/filename>

On Mac OS X, you should use colons to separate directories in the TraceOutputFileName path rather than slashes.

Note: Beginning with the Flash Player 9 Update, Flash Player ignores the TraceOutputFileName property and stores the flashlog.txt file in a hard-coded location based on operating system. For more information, see the section on log file location listed below.


http://livedocs.adobe.com/flex/3/html/help.html?content=logging_04.html
另外还有一些参数可以输出代码执行中的调用堆栈啦什么的,参数给忘记了,想起了再补上

关于flex中设置帧频的问题

    flex对flash进行了一定的封装,使得flex的思想与flash已经有些不同,所以在处理问题上也一定要小心一些陷阱,否则出现的一些BUG会让人觉得莫名其秒,这次我就遇到一个BUG,折磨了好些时间
    在flash中要想动态修改帧频只要在程序中stage.frameRate=myFrameRate就可以了,所以想当然在flex里也应该这样,顶多修改为Application.application.frameRate=myFrameRate,但问题确出现了,我是在一个swfLoader的complete事件里做的处理,修改帧频,侦听一个加载内容播放结束的事件然后再改回去,结果失败,怎么改系统帧频就是没变,
    在侦听器里加又加了个enter_frame事件处理器输出帧频发现又被改回去了,
    在enter_frame事件处理器中持续修改帧频为需要的帧频,debug下正常了,高兴一上,但网页中打开一看,速度巨快,
    在修改帧频前打印系统帧频,为1000,猜想肯定是flex在做怪
    直接用文本搜索软件搜SDK中的frameRate,在LayoutManager中发现了,找到原因了,
    
    flex思想:有属性发生改变,invalidate,渲染推迟,render事件中,如果有invalidate,则保存当前帧频,修改帧频为1000,开始对所有对象进行validate,直到全部validated,这个过程有可能在不至一个enter_frame中完成,而这段时间内帧频一直是1000

2010年10月14日星期四

理解as3 Function中的this

这里Function有两个称呼:类中的叫方法,其它的叫函数,而Function中的this因这两种情况其this值是不一样的
在类中,this指向该方法的关联对象
函数,this指向该函数的调用者

如:
var c1:C1=new C1(); 
var c2:C2=new C2();

var f:Function = function(){
   trace(this); 
   this.doSomthing();
};

f.call(null); //调用者为global
f.call(c1);  //调用者(或者叫关联者更贴切)为c1,doSomthing为C1中的方法
f.call(c2);  //调用者(或者叫关联者更贴切)为c2,doSomthing为C2中的方法

as3中arguments对象

手册上解释:该对象用于存储和访问函数参数,所以在Function对象初始化时内部直接拥有一个arguments对象,而该对象有两个属性:
    callee:访问其所在函数的引用
    length:参数个数

对象arguments.callee就有一个用武之地:
有很多时候会定义一个匿名的事件侦听器,如:
  mc.addEventListener(
    "my_e_type",
    function (e:Event){
    }
  );
这样的话就会出现定义的这个侦听器无法删除,如果这个mc被使用多次,就会造出多个侦听器,最终出现错误,这时候就可以使用上面提到的方法来在匿名函数中删除侦听器了:
  mc.addEventListener(
    "my_e_type",
    function (e:Event){
      mc.removeEventListener(""my_e_type",arguments.callee);
      
      //some code
    }
  );

2010年10月6日星期三

关注两款游戏

关注一下两款游戏:征途2,据说是以电影的手法来做游戏;大兵小将,回合制RPG,看画面还不错

2010年9月26日星期日

adobe melrose

adobe与intel联合开发的melrose sdk,用于打包adobe air/flex应用,便于部署到adobe marketplace和intel appUp上去,其实思路上应该就像Google App Engine 的SDK吧!

写给迷茫而兴奋的程序员――从需求来开始自己的项目

有时有些迷茫而兴奋的程序员会发布这样的消息:

大家好!我刚学会Erlang/Haskell/Python,现在想找个大项目练练手。如果你有什么好主意,一定要告诉我!

  或

我喜欢Linux和开源,想开发一个项目为社区做点贡献。有没有这样一个重要的程序,它只有Windows版,而你想开发Linux版呢?

  这些错误的请求方式令人困惑。焦点都放在了程序语言、操作系统和软件许可上。根本没考虑到解决问题,有用性,或者程序跟最初信息发布者之间的关系。你会相信一个不懂音乐的人开发的音符软件吗?你会相信一个从未用过Photoshop的人开发的Photoshop复制品吗?

  这些人不妨看看以下建议:

  静下心来,想想你的个人兴趣,然后解决和你的个人兴趣相关的一个简单问题。比如我跟着一个打鼓机学吉他,但我想给鼓添加点人性化元素,比如自动填写等功能。于是我写了一个打鼓测序程序,没有图形用户界面,试了试效果。我还拍了很多照片,并使用了一个标签方案(tagging scheme)。这事很简单,我一个下午就搞定了。

  关键有两点:(1)简单,(2)开发点你会真正使用的东西。

  取得初步成功之后,你就可以开发一系列改进版本。不要急于求成,一下子拿个公测版出来,只需检查现有程序,不断改进就好。我可以给自己的图片标签器添加一个HTML5前端界面吗?

  如果坚持重复几次,你就会成为一个专家,或许这个专家仅限于解决你的个人问题,但别拿豆包不当干粮。成为一个专家还有一个好处:你可以尝试以前看似神秘甚至不可能实现的改进和功能。正是这些改进和功能有可能突然之间让你的程序一炮走红。

app开发

app开发会是一个趋势,包括手机应用开发,chrome应用开发,社交应用开发,及各种开放平台的应用开发,平台+服务是以后互联网的形态

as3中的命名空间

学会去使用它

linux

linux使用越来越广泛了

Programming ActionScript 3.0 > Using the external API > Using the ExternalInterface class

http://livedocs.adobe.com/flash/9.0/main/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Parts&file=00000344.html

flash cs3关于外部调用swf中方法的一些资料,

swf文件研究

这篇日志我会持续更新的,因为学习这个东西不是一晚上就能搞通的,而且这晚上还有其它的事情要做。
先记录一下了解到的一些东西,首先是列出一个大纲,该怎么研究下去
第一、swf的格式,swf应该是由tag和对应的数据构成,其中应该有一个doABC标签,该标签下保存as文件的字节码内容abc文件;
第二、接下来就应该了解一下abc文件的文件结构了,如:abc中的常量池

有些参考博客:

看onLive服务

        onLive服务是一种网络游戏云计算实现方案,本质上就是所有运算都交给服务器去计算,然后服务器生成出游戏画面,发到客户机里显示即可,这样的服务可以做到只用一台普通的电脑甚至手机也可以玩高质量的3D游戏,唯一要担心的是网络够不够快,一个新名词是GOD(游戏点播)
        这是一种b/s更深层次的应用,也应该是种启发,以后在项目当中可以以这种思想来拓展一下思路,更好的理解一下服务端客户端的分工和协作,现在不是有款网页游戏王国印记号称其纸娃娃系统就采用了类似的方案,当avatar换装后由服务端运算生成相应的一张图像由客户端加载显示
        在如此快节奏,如此浮躁的今天,瘦客户端一定是趋势

2010年9月16日星期四

骏梦游戏的《小小忍者》

上海骏梦游戏将在9月25日,旗下网页游戏《小小忍者》开始技术封测,据说这款游戏中采用了Unity 3D技术,有诸多亮点,关注一下

2010年9月14日星期二

如何进行大规模重构

  大规模重构很难做,做好这项工作的关键在于要识别出起点,然后沿着路线小步前进.

2010年9月5日星期日

关注一下chrome OS

    看到一篇文章在说chrome os将来超越windows的三个优势:移动、带宽和云。然后分析了chrome os里的两个真正“杀手级”级的东西:Chromting和native client,前者没怎么听过,说是个远程桌面的东西,而后者相当于windows ie下的activeX的东西,就是一个LLVM级别的虚拟机,可以用很多语言来为chrome编写插件,实现诸如office的东西。
    因chrome os本是为网络而生的操作系统,理念上它里面只有一个应用chrome浏览器,该系统下运行的所有东西都是互联网下的一个服务,数据存储在云中,再看google现在布局:GAE、google storage from develop,GAE方便开发者开发一个服务,而google storage则提供了云中数据存储。
    native client则为用户提供了网络之外的另一种选择

    互联网向服务化发展,但这样的一个操作系统会成功吗?期待……

2010年9月1日星期三

Simple way to execute multiple process in parallel « Python recipes « ActiveState Code

http://code.activestate.com/recipes/577376-simple-way-to-execute-multiple-process-in-parallel/

---
This message was sent by fancle.zhang@gmail.com via http://addthis.com. Please note that AddThis does not verify email addresses.

Make sharing easier with the AddThis Toolbar: http://www.addthis.com/go/toolbar-em

python的函数修饰符

看一个例子:


def require_int (func):
def wrapper (arg):
assert isinstance(arg, int)
return func(arg)
return wrapper


@require_int
def p1 (arg):
print arg


其中@require_int就是一个函数修饰符了,本质上函数修饰符就是一个函数,只是对定义在它下面的函数进行一次修改,如上面的例子,应用函数修饰符原理是这么执行的:
p1 = require_int(p1)


这里这个修饰符的功能是检查函数的参数类型是否为整数


更高级一点是函数修饰符可以也可以带参数的,看下面这个例子:

def synchronized(lock):
    """ Synchronization decorator. """

    def wrap(f):
        def newFunction(*args, **kw):
            lock.acquire()
            try:
                return f(*args, **kw)
            finally:
                lock.release()
        return newFunction
    return wrap

if __name__ == '__main__':
    from threading import Thread, Lock
    import time
    import os

    myLock = Lock()

    class MyThread(Thread):
        def __init__(self, n):
            Thread.__init__(self)
            self.n = n

        @synchronized(myLock)
        def run(self):
            """ Print out some stuff.

            The method sleeps for a second each iteration.  If another thread
            were running, it would execute then.
            But since the only active threads are all synchronized on the same
            lock, no other thread will run.
            """

            for i in range(5):
                print 'Thread %d: Start %d...' % (self.n, i),
                time.sleep(1)
                print '...Thread %d: Stop [%d].' % (self.n, i)

    threads = [MyThread(i) for i in range(2)]
    for t in threads:
        t.start()

    for t in threads:
        t.join()

    os.system("PAUSE")

这里他的原理上是这么执行的:
temp = synchronized(lock)
run = temp(run)

百度的框计算——从内容到服务,互联网的变革

百度推出了牛逼的框计算,又一起标志互联网转型的先驱。
互联网已由传统的提供内容向提供服务来转变

2010年8月31日星期二

CMD命令大全


CMD命令大全
关某个命令的详细信息,请键入 HELP 命令名  
XP.CMD命令大全   有关某个命令的详细信息,请键入 HELP 命令名 
ASSOC 显示或修改文件扩展名关联。
AT 计划在计算机上运行的命令和程序。 
ATTRIB 显示或更改文件属性。 
BREAK 设置或清除扩展式 CTRL+C 检查。 
CACLS 显示或修改文件的访问控制列表(ACLs)。 
CALL 从另一个批处理程序调用这一个。 
CD 显示当前目录的名称或将其更改。 
CHCP 显示或设置活动代码页数。 
CHDIR 显示当前目录的名称或将其更改。 
CHKDSK 检查磁盘并显示状态报告。 
CHKNTFS 显示或修改启动时间磁盘检查。 
CLS 清除屏幕。 
CMD 打开另一个 Windows 命令解释程序窗口。 
COLOR 设置默认控制台前景和背景颜色。
COMP 比较两个或两套文件的内容。 
COMPACT 显示或更改 NTFS 分区上文件的压缩。 
CONVERT 将 FAT 卷转换成 NTFS。您不能转换 当前驱动器。 
COPY 将至少一个文件复制到另一个位置。 
DATE 显示或设置日期。 
DEL 删除至少一个文件。 
DIR 显示一个目录中的文件和子目录。 
DISKCOMP 比较两个软盘的内容。 
DISKCOPY 将一个软盘的内容复制到另一个软盘。 
DOSKEY 编辑命令行、调用 Windows 命令并创建宏。 
ECHO 显示消息,或将命令回显打开或关上。 
ENDLOCAL 结束批文件中环境更改的本地化。 
ERASE 删除至少一个文件。 
EXIT 退出 CMD.EXE 程序(命令解释程序)。 
FC 比较两个或两套文件,并显示 不同处。 
FIND 在文件中搜索文字字符串。 
FINDSTR 在文件中搜索字符串。 
FOR 为一套文件中的每个文件运行一个指定的命令。 
FORMAT 格式化磁盘,以便跟 Windows 使用。 
FTYPE 显示或修改用于文件扩展名关联的文件类型。 
GOTO 将 Windows 命令解释程序指向批处理程序 中某个标明的行。 
GRAFTABL 启用 Windows 来以图像模式显示 扩展字符集。 
HELP 提供 Windows 命令的帮助信息。 
IF 执行批处理程序中的条件性处理。
LABEL 创建、更改或删除磁盘的卷标。 
MD 创建目录。 
MKDIR 创建目录。 
MODE 配置系统设备。 
MORE 一次显示一个结果屏幕。 
MOVE 将文件从一个目录移到另一个目录。 
PATH 显示或设置可执行文件的搜索路径。 
PAUSE 暂停批文件的处理并显示消息。 
POPD 还原 PUSHD 保存的当前目录的上一个值。 
PRINT 打印文本文件。 
PROMPT 更改 Windows 命令提示符。 
PUSHD 保存当前目录,然后对其进行更改。 
RD 删除目录。 
RECOVER 从有问题的磁盘恢复可读信息。 
REM 记录批文件或 CONFIG.SYS 中的注释。 
REN 重命名文件。 
RENAME 重命名文件。 
REPLACE 替换文件。 
RMDIR 删除目录。 
SET 显示、设置或删除 Windows 环境变量。 
SETLOCAL 开始批文件中环境更改的本地化。 
SHIFT 更换批文件中可替换参数的位置。 
SORT 对输入进行分类。 
START 启动另一个窗口来运行指定的程序或命令。 
SUBST 将路径跟一个驱动器号关联。 
TIME 显示或设置系统时间。 
TITLE 设置 CMD.EXE 会话的窗口标题。 
TREE 以图形模式显示驱动器或路径的目录结构。 
TYPE 显示文本文件的内容。 
VER 显示 Windows 版本。 
VERIFY 告诉 Windows 是否验证文件是否已正确 写入磁盘。 
VOL 显示磁盘卷标和序列号。 
XCOPY 复制文件和目录树。   
appwiz.cpl------------添加删除程序  
control userpasswords2--------用户帐户设置  
cleanmgr-------垃圾整理  
CMD--------------命令提示符可以当作是 Windows 的一个附件,
Ping,Convert 这些不能在图形环境下 使  用的功能要借助它来完成。  
cmd------jview察看Java虚拟机版本。   
command.com------调用的则是系统内置的 NTVDM,一个 DOS虚拟机。它完全是一个类似 Virtual PC 的   虚拟环境,和系统本身联系不大。当我们在命令提示符下运行 DOS 程序时,实际上也 是自动转移到   NTVDM虚拟机下,和 CMD 本身没什么关系。   
calc-----------启动计算器  
chkdsk.exe-----Chkdsk磁盘检查  
compmgmt.msc---计算机管理  
conf-----------启动 netmeeting  
control userpasswords2-----User Account 权限设置  
devmgmt.msc--- 设备管理器  
diskmgmt.msc---磁盘管理实用程序  
dfrg.msc-------磁盘碎片整理程序  
drwtsn32------ 系统医生  
dvdplay--------启动Media Player  
dxdiag-----------DirectX Diagnostic Tool  
gpedit.msc-------组策略编辑器  
gpupdate /target:computer /force 强制刷新组策略  
eventvwr.exe-----事件查看器  
explorer-------打开资源管理器  
logoff---------注销命令  
lusrmgr.msc----本机用户和组  
msinfo32---------系统信息  
msconfig---------系统配置实用程序  
net start (servicename)----启动该服务  
net stop (servicename)-----停止该服务  
notepad--------打开记事本  
nusrmgr.cpl-------同control userpasswords,打开用户帐户控制面板  
Nslookup-------IP地址侦测器  
oobe/msoobe /a----检查XP是否激活  
perfmon.msc----计算机性能监测程序  
progman--------程序管理器  
regedit----------注册表编辑器  
regedt32-------注册表编辑器  
regsvr32 /u *.dll----停止dll文件运行  
route print------查看路由表   
rononce -p ----15秒关机  
rsop.msc-------组策略结果集  
rundll32.exe rundll32.exe %Systemroot%System32shimgvw.dll,ImageView_Fullscreen----启动一个空白  的Windows 图片和传真查看器  
secpol.msc--------本地安全策略  
services.msc---本地服务设置  
sfc /scannow-----启动系统文件检查器  
sndrec32-------录音机  
taskmgr-----任务管理器(适用于2000/xp/2003)  
tsshutdn-------60秒倒计时关机命令  
winchat--------XP自带局域网聊天  
winmsd---------系统信息  
winver-----显示About Windows 窗口  
wupdmgr-----------Windows Update 

2010年8月30日星期一

python标准import

标准Import

Python中所有加载到内存的模块都放在sys.modules。当import一个模块时首先会在这个列表中查找是否已经加载了此模块,如果加载了则只是将模块的名字加入到正在调用import的模块的Local名字空间中。如果没有加载则从sys.path目录中按照模块名称查找模块文件,模块文件可以是py、pyc、pyd,找到后将模块载入内存,并加入到sys.modules中,并将名称导入到当前的Local名字空间。

可以看出了,一个模块不会重复载入。多个不同的模块都可以用import引入同一个模块到自己的Local名字空间,其实背后的PyModuleObject对象只有一个。

说一个容易忽略的问题,import只能导入模块,不能导入模块中的对象(类、函数、变量等)。如一个模块A(A.py)中有个函数getName,另一个模块不能通过import A.getName将getName导入到本模块,只能用import A。如果想只导入特定的类、函数、变量则用from A import getName即可。

嵌套Import

嵌套import,我分两种情况,一种是:本模块导入A模块(import A),而A中又有import语句,会激活另一个import动作,如import B,而B模块又可以import其他模块,一直下去。

对这种嵌套比较容易理解,注意一点就是各个模块的Local名字空间是独立的,所以上面的例子,本模块import A完了后本模块只能访问模块A,不能访问B及其他模块。虽然模块B已经加载到内存了,如果要访问还要在明确的在本模块中import B。

另外一种嵌套指,在模块A中import B,而在模块B中import A。这时会怎么样呢?这个在Python列表中由RobertChen给出了详细解释,抄录如下:

[A.py]   from B import D   class C:pass    [B.py]   from A import C   class D:pass 

为什么执行A的时候不能加载D呢?

如果将A.py改为:import B就可以了。

这是怎么回事呢?

RobertChen:这跟Python内部import的机制是有关的,具体到from B import D,Python内部会分成几个步骤:

  1. 在sys.modules中查找符号"B"
  2. 果符号B存在,则获得符号B对应的module对象<module B>。

    从<module B>的__dict__中获得符号"D"对应的对象,如果"D"不存在,则抛出异常

  3. 如果符号B不存在,则创建一个新的module对象<module B>,注意,这时,module对象的__dict__为空。

    执行B.py中的表达式,填充<module B>的__dict__ 。

    从<module B>的__dict__中获得"D"对应的对象,如果"D"不存在,则抛出异常。

所以,这个例子的执行顺序如下:

1、执行A.py中的from B import D

由于是执行的python A.py,所以在sys.modules中并没有<module B>存在,首先为B.py创建一个module对象(<module B>),注意,这时创建的这个module对象是空的,里边啥也没有,在Python内部创建了这个module对象之后,就会解析执行B.py,其目的是填充<module B>这个dict。

2、执行B.py中的from A import C

在执行B.py的过程中,会碰到这一句,首先检查sys.modules这个module缓存中是否已经存在<module A>了,由于这时缓存还没有缓存<module A>,所以类似的,Python内部会为A.py创建一个module对象(<module A>),然后,同样地,执行A.py中的语句。

3、再次执行A.py中的from B import D

这时,由于在第1步时,创建的<module B>对象已经缓存在了sys.modules中,所以直接就得到了<module B>,但是,注意,从整个过程来看,我们知道,这时<module B>还是一个空的对象,里面啥也没有,所以从这个module中获得符号"D"的操作就会抛出异常。如果这里只是import B,由于"B"这个符号在sys.modules中已经存在,所以是不会抛出异常的。

上面的解释已经由Zoom.Quiet收录在啄木鸟了,里面有图,可以参考一下。

Package(包) Import

包(Package)可以看成模块的集合,只要一个文件夹下面有个__init__.py文件,那么这个文件夹就可以看做是一个包。包下面的文件夹还可以成为包(子包)。更进一步,多个较小的包可以聚合成一个较大的包,通过包这种结构,方便了类的管理和维护,也方便了用户的使用。比如SQLAlchemy等都是以包的形式发布给用户的。

包和模块其实是很类似的东西,如果查看包的类型import SQLAlchemy type(SQLAlchemy),可以看到其实也是<type 'module'>。import包的时候查找的路径也是sys.path。

包导入的过程和模块的基本一致,只是导入包的时候会执行此包目录下的__init__.py而不是模块里面的语句了。另外,如果只是单纯的导入包,而包的__init__.py中又没有明确的其他初始化操作,那么此包下面的模块是不会自动导入的。如:

PA

--__init__.py

--wave.py

--PB1

  --__init__.py

  --pb1_m.py

--PB2

  --__init__.py

  --pb2_m.py

__init__.py都为空,如果有以下程序:

 
  1. import sys
  2. import PA.wave  #1
  3. import PA.PB1   #2
  4. import PA.PB1.pb1_m as m1  #3
  5. import PA.PB2.pb2_m #4
  6. PA.wave.getName() #5
  7. m1.getName() #6
  8. PA.PB2.pb2_m.getName() #7

当执行#1后,sys.modules会同时存在PA、PA.wave两个模块,此时可以调用PA.wave的任何类或函数了。但不能调用PA.PB1(2)下的任何模块。当前Local中有了PA名字。

当执行#2后,只是将PA.PB1载入内存,sys.modules中会有PA、PA.wave、PA.PB1三个模块,但是PA.PB1下的任何模块都没有自动载入内存,此时如果直接执行PA.PB1.pb1_m.getName()则会出错,因为PA.PB1中并没有pb1_m。当前Local中还是只有PA名字,并没有PA.PB1名字。

当执行#3后,会将PA.PB1下的pb1_m载入内存,sys.modules中会有PA、PA.wave、PA.PB1、PA.PB1.pb1_m四个模块,此时可以执行PA.PB1.pb1_m.getName()了。由于使用了as,当前Local中除了PA名字,另外添加了m1作为PA.PB1.pb1_m的别名。

当执行#4后,会将PA.PB2、PA.PB2.pb2_m载入内存,sys.modules中会有PA、PA.wave、PA.PB1、PA.PB1.pb1_m、PA.PB2、PA.PB2.pb2_m六个模块。当前Local中还是只有PA、m1。

下面的#5,#6,#7都是可以正确运行的。

注意的是:如果PA.PB2.pb2_m想导入PA.PB1.pb1_m、PA.wave是可以直接成功的。最好是采用明确的导入路径,对于./..相对导入路径还是不推荐用。