<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title type="text">博客园_万仓一黍</title><subtitle type="text">代码随笔</subtitle><id>http://feed.cnblogs.com/blog/u/61830/rss</id><updated>2012-05-14T03:19:26Z</updated><author><name>万仓一黍</name><uri>http://www.cnblogs.com/grenet/</uri></author><generator>feed.cnblogs.com</generator><link rel="alternate" type="text/html" href="http://www.cnblogs.com/grenet/"/><link rel="self" type="application/atom+xml" href="http://feed.cnblogs.com/blog/u/61830/rss"/><entry><id>http://www.cnblogs.com/grenet/archive/2012/05/14/2499069.html</id><title type="text">转自51CTO的帖子——宅男程序员给老婆的计算机课程</title><summary type="text">在51CTO上闲逛的时候，看了这个系列的帖子。感觉不错，特转发于此，留做纪念。 原文链接： 宅男程序员给老婆的计算机课程之0：认清本质 宅男程序员给老婆的计算机课程之1：认清实际 宅男程序员给老婆的计算机课程之2：怎么看待牛人 宅男程序员给老婆的计算机课程之3：架构比较 宅男程序员给老婆的计算机课程之4：SQL vs NoSQL 宅男程序员给老婆的计算机课程之5：设计模式 宅男程序员给老婆的计算机课程之6：模版引擎 宅男程序员给老婆的计算机课程之7：运维的重要性 宅男程序员给老婆的计算机课程之8：控制器 宅男程序员给老婆的计算机...</summary><published>2012-05-14T03:19:00Z</published><updated>2012-05-14T03:19:00Z</updated><author><name>万仓一黍</name><uri>http://www.cnblogs.com/grenet/</uri></author><link rel="alternate" href="http://www.cnblogs.com/grenet/archive/2012/05/14/2499069.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/grenet/archive/2012/05/14/2499069.html"/><content type="html">&lt;p&gt;在51CTO上闲逛的时候，看了这个系列的帖子。感觉不错，特转发于此，留做纪念。&lt;/p&gt;&lt;p&gt;原文链接：&lt;/p&gt;&lt;p&gt;&lt;a href="http://developer.51cto.com/art/201202/314296.htm"&gt;宅男程序员给老婆的计算机课程之0：认清本质&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://developer.51cto.com/art/201202/315330.htm"&gt;宅男程序员给老婆的计算机课程之1：认清实际&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://developer.51cto.com/art/201202/316160.htm"&gt;宅男程序员给老婆的计算机课程之2：怎么看待牛人&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://developer.51cto.com/art/201202/317179.htm"&gt;宅男程序员给老婆的计算机课程之3：架构比较&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://developer.51cto.com/art/201202/317596.htm"&gt;宅男程序员给老婆的计算机课程之4：SQL vs NoSQL&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://developer.51cto.com/art/201202/318911.htm"&gt;宅男程序员给老婆的计算机课程之5：设计模式&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://developer.51cto.com/art/201203/320926.htm"&gt;宅男程序员给老婆的计算机课程之6：模版引擎&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://developer.51cto.com/art/201203/321540.htm"&gt;宅男程序员给老婆的计算机课程之7：运维的重要性&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://developer.51cto.com/art/201203/324226.htm"&gt;宅男程序员给老婆的计算机课程之8：控制器&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://developer.51cto.com/art/201203/325510.htm"&gt;宅男程序员给老婆的计算机课程之9：数据模型&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://developer.51cto.com/art/201204/332048.htm"&gt;宅男程序员给老婆的计算机课程之10：做，就对了！&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://developer.51cto.com/art/201205/333568.htm"&gt;宅男程序员给老婆的计算机课程之11：域模型&lt;/a&gt;&lt;/p&gt;&lt;p&gt;出于对原文的尊重，把原文链接放在上面。浏览本文的，如果觉得文章不错，可以点上面的链接，增加文章的访问量。&lt;/p&gt;&lt;p&gt;下面是该系列文章的转帖：&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;【51CTO独家特稿】从今天起将开始的这个系列来自一位宅男程序员，这个系列是他写给老婆的电脑课程，后来经他老婆的建议，决定在51CTO这个平台上公开出来与大家分享。&lt;/p&gt;&lt;p&gt;在系列开始之前，先介绍一下两位主人公&amp;#8212;&amp;#8212;&lt;/p&gt;&lt;p&gt;男主角：Wuvist（新浪微博），真名翁伟，自称胖程序员一个，幸好已婚。学习.net出身，现常用python做服务器端开发，曾任新加坡某创业公司主程。公司被techcrunch blog过后，觉得新加坡生活太过安逸，终于于去年辞职只身回家乡汕头创业，活跃于珠三角技术沙龙，热衷于与其他技术宅分享。&lt;/p&gt;&lt;p&gt;女主角：Katze，Wuvist的老婆，女程序员，在某跨国投行任Unix系统管理员，常被Wuvist嘲笑技术太差。&lt;/p&gt;&lt;p&gt;总之，因Wuvist只身回国创业，这对分隔天涯的技术宅男宅女竟然想出了定期写技术课程、交作业这种方式来保持联系，这何止是令人发指？简直就是令人发指！&lt;/p&gt;&lt;p&gt;技术宅的你，想看看他们究竟是如何令人发指吗？以下，开始本系列的第0篇&amp;#8212;&amp;#8212;认清本质。&lt;/p&gt;&lt;p&gt;新加坡国立大学计算机系有两门课：CS 1101 / 1102。&lt;/p&gt;&lt;p&gt;几乎所有的大学计算机系课程都有两门类似的课程；但几乎所有的学生都误解了这两门课；以为前者是教C，后者是教Java；但实际上前者是 Programming Methodology 后者是 Data Structure and Algorithm。&lt;/p&gt;&lt;p&gt;所以这两门课可以有选择，1101c 或者 1101s，使用不同的语言作为媒介。语言并不重要。&lt;/p&gt;&lt;p&gt;只要掌握了编程的思想、数据结构、算法，使用不同的语言去表达是很容易的。&lt;/p&gt;&lt;p&gt;会了很多种电脑语言后，学一门新的编程语言，几乎只要花一个晚上看看官方的语法文档就可以立刻开始使用做东西了。最多就一个星期。&lt;/p&gt;&lt;p&gt;基本上，那些说长时间说自己在学C#，学java的程序员，都是2B程序员，他们完全不懂得程序开发中&amp;#8220;思想&amp;#8221;、&amp;#8220;数据结构&amp;#8221;、&amp;#8220;算法&amp;#8221;的本质，而将大量的时间耗费在语言实现的细枝末梢中，纯粹浪费自己时间。&lt;/p&gt;&lt;p&gt;不同的语言会有不同的特性，有一些特性是比较重要的，普遍存在于多种语言当中的，&amp;#8220;学习&amp;#8221;一种新语言，实际上仅需要查看文档，看这种语言是以怎样的语法支持这些特性而已。&lt;/p&gt;&lt;p&gt;OO是影响很广的编程概念，基本上，是Enterprise Developer（注：企业级开发者）的圣经、法则。&lt;/p&gt;&lt;p&gt;ED认为，越OO越好。&lt;/p&gt;&lt;p&gt;基本上，计算机业界有两批人，一批是真正的程序员，或者说hacker，一批就是ED。&lt;/p&gt;&lt;p&gt;ED实际上是企业的工具，他们很少有自己创新的想法；企业说啥米，就做啥米。所以，会有大量的vender，提供工具、支持、新技术，去train这些ED。&lt;/p&gt;&lt;p&gt;典型的vender有微软、IBM、Oracle等等；这些vender为了向企业推销产品，他们就经常会鼓吹一些新的&amp;#8220;技术&amp;#8221;，然后打包成为解决方案，推销给企业。&lt;/p&gt;&lt;p&gt;为了鼓吹、宣传这些技术，还有一批企业是专门在&amp;#8220;布道&amp;#8221;的，他们是所谓的&amp;#8220;咨询公司&amp;#8221;。&lt;/p&gt;&lt;p&gt;这样的咨询公司，他们会专门聘用一些所谓&amp;#8220;Evangelist&amp;#8221;，屁事不做，整天四处布道，名头都很牛逼，如XX金牌讲师。&lt;/p&gt;&lt;p&gt;他们实质上，就是推销员，只是，他们推销的产品，是所谓的&amp;#8220;新技术&amp;#8221;而已。&lt;/p&gt;&lt;p&gt;微软在新加坡好像就招了不少Evangelist 。每隔几年，微软所推广的技术就会&amp;#8220;革新&amp;#8221;一次，Evangelist们就不断的四处去宣传新技术改变了一切，能够提高效率无数倍。&lt;/p&gt;&lt;p&gt;Evangelist本身的技术，很多是很差的；就好像推销员本身，是不会做产品开发、不懂技术的。他们仅仅是会宣传、鼓吹新技术而已；满口各种新技术名词，但他们本身，可能仅仅只是会使用这些技术写一个Hello World。&lt;/p&gt;&lt;p&gt;因为他们本身素质很差，所以，他们是无法分辨他们所推广的技术本身是否好，他们只是复读机。有时候，vender本身在推的技术也其实不错，但复读机们也会把它夸张到荒谬的地步。&lt;/p&gt;&lt;p&gt;OO就是一个典型。&lt;/p&gt;&lt;p&gt;OO仅仅是无数编程模型中的一种而已，但它被过度的夸张，诠释。&lt;/p&gt;&lt;p&gt;Hacker们写程序，基本不会去追求程序本身是否符合OO规范。Hack这个词的意义本身就在于打破规范。&lt;/p&gt;&lt;p&gt;但是，大多数的ED是很笨的，他们缺乏独立思考的能力，他们需要被Train，而无法自学。Hacker的那套，他们接受不来。&lt;/p&gt;&lt;p&gt;所以，才会有vender / consultant / 培训学校一系列的产业，去鼓吹：&lt;/p&gt;&lt;p&gt;OO、XML、SOAP、Web Service、Silverlight等等一系列伪技术。&lt;/p&gt;&lt;p&gt;有的ED，一辈子都无法意识到他们实际上是中了vender的圈套；无法掌握真正的编程技术，而沉迷于vender们所鼓吹的&amp;#8220;新技术&amp;#8221;，一代接一代。&lt;/p&gt;&lt;p&gt;然后，只要有其中的一代技术ED没能掌握，ED就立刻被淘汰了；因为这种ED，穷其一生都没有学会真正的编程；他们仅仅是学会了一代又一代的被封装的伪技术使用技巧而已。&lt;/p&gt;&lt;p&gt;伪技术的典型特征是封装。&lt;/p&gt;&lt;p&gt;它本身没有任何新的东西，只是把旧的技术封装一下，换汤不换药而已。&lt;/p&gt;&lt;p&gt;OO是最好的封装技术；所以它被无底线的推崇。&lt;/p&gt;&lt;p&gt;封装很重要；但是，对于程序员来说，掌握封装技术本身，跟学习使用别人封装好的技术工具；是两回事。&lt;/p&gt;&lt;p&gt;&amp;#8220;程序员从此不再需要关心XXX&amp;#8221;，这是evangelist最常用的宣传语句；2B ED，看了就很高兴，然后拼命去学习新的&amp;#8220;技术&amp;#8221;，把他们曾经掌握的XXX底层技术给忘掉。&lt;/p&gt;&lt;p&gt;微软所宣传的理念被Hacker理解为&amp;#8220;Even monkeys can code&amp;#8221;。ED被evangelist鼓吹的新技术洗脑，最终就是成为monkey而已；所做的工作，毫无技术含量；很容易被淘汰。&lt;/p&gt;&lt;p&gt;所谓的程序员30岁必须转行这种说法，便是源于ED被洗脑。&lt;/p&gt;&lt;p&gt;这种ED，从未掌握真正的编程技术，是必然被淘汰的。&lt;/p&gt;&lt;p&gt;而这种ED，在大学时，就是把cs 1101 / 1102理解成为教 c / 教 java的那群人。&lt;/p&gt;&lt;p&gt;他们，从一开始就走错了。&lt;/p&gt;&lt;p&gt;作业（编辑说明：在技术宅和他老婆的故事中，只有女主人公完成作业之后，男主人公才会发出新课程。当然，身为看客的您可以无需完成这些作业，但如果您仍是学生，或者您正在带学生或小弟的话，倒是可以做个参考）：&lt;/p&gt;&lt;p&gt;1. 用500字讲述什么是Programming Methodology?&lt;/p&gt;&lt;p&gt;2. 列举10种Data Structure.&lt;/p&gt;&lt;p&gt;3. 列举10种Algorithm.&lt;/p&gt;&lt;p&gt;【作者声明】Katze实际上是正宗计算机系科班出身，而且大学成绩甩开Wuvist九条街，这其中还包括算法、计算机架构等传统上被技术宅男垄断的科目。Katze毕业后长期于投行从事Unix服务器运维工作，故研发编码水平会被Wuvist嘲笑；但Wuvist不会写shell脚本时，绝对是第一时间向Katze求助。&lt;/p&gt;&lt;p&gt;Wuvist写的这系列教程以及作业安排，是为Katze量身定做的，像第1课的作业便因此会出现Perl这门研发中不常用，但在运维中却非常普遍的语言。这系列Wuvist是写给老婆的私人课程，其中充满了各种主观偏见，有缘发布到51CTO来，各位看官若看得不爽，请尽管抛砖头狠踩，但是请尽量喷得准确、到位、凶狠一些～&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&amp;#8220;算法&amp;#8221;、&amp;#8220;数据结构&amp;#8221;等，是本质；很重要，需要掌握，但一般开发时，很少需要自己去实现。&lt;/p&gt;&lt;p&gt;觉得多数开发，是&amp;#8220;拚积木&amp;#8221;。&lt;/p&gt;&lt;p&gt;即便是业务逻辑需要对一些数据进行排序，也不可能自己去实现一个quicksort算法；而是直接调用quicksort的现成类库。&lt;/p&gt;&lt;p&gt;这也直接造成了2B ED穷其一生都不能掌握真正的编程能力。&lt;/p&gt;&lt;p&gt;他们认为，能够&amp;#8220;解决&amp;#8221;问题就好，至于问题是怎么解决的，他们并不关心。&lt;/p&gt;&lt;p&gt;对于细节的认识、掌控能力，直接造成了水平的天渊之别。&lt;/p&gt;&lt;p&gt;以拍照为例子，以前人们用傻瓜相机，现在人们用iPhone去拍照；很快，很方便，还可以加滤镜。&lt;/p&gt;&lt;p&gt;但是，普通人们在不了解什么是光圈、精深、背光等概念的情况下，是没有可能成为摄影师的。&lt;/p&gt;&lt;p&gt;即便他们放下iPhone拿起DSLR。&lt;/p&gt;&lt;p&gt;普通人跟摄影师拍摄同样的东西；出来的照片也许会差不多，但如果深入去比较，景深、角度、光线、取景等等等等细节，则都会有差别，而这些差别积累起来，就造成了普通照片与摄影作品的差别。&lt;/p&gt;&lt;p&gt;画家要画好画，必然要对画笔、颜料、纸张的特性有深入的了解。&lt;/p&gt;&lt;p&gt;厨师要做好菜，必然要了解食材的特性，对调味料、厨具等有娴熟的掌控。&lt;/p&gt;&lt;p&gt;ED的&amp;#8220;解决问题就好&amp;#8221;，跟没有下过厨房的千金小姐拿着菜谱使用微波炉做菜没啥区别。&lt;/p&gt;&lt;p&gt;在大厨手里，微波炉也可以是神器；但：&lt;/p&gt;&lt;p&gt;&amp;#8220;有的人，纵然神刀在手，亦无法成为刀中之神。&amp;#8221;&lt;/p&gt;&lt;p&gt;程序员要&amp;#8220;拚好积木&amp;#8221;，那必然需要对积木的种类、材质、特性，有深入的了解。&lt;/p&gt;&lt;p&gt;总得对quicksort的实现有认识，才能够用好quicksort。在有的场景下，quicksort的性能反而是最差的。如果不了解，就无法去把quicksort用好。&lt;/p&gt;&lt;p&gt;程序开发中，有一个著名的 80 / 20 原则。&lt;/p&gt;&lt;p&gt;我想，这个原则也可以适用于ED。&lt;/p&gt;&lt;p&gt;程序员只要花20%的努力就可以成为一个混日子的ED；80%的程序员均是如此。&lt;/p&gt;&lt;p&gt;但如果要成为一个优秀的程序员甚至hacker，那么，需要花多至少4倍的努力。&lt;/p&gt;&lt;p&gt;有什么积木可以用？积木本身是怎么做的？积木A比积木B好在哪里？&lt;/p&gt;&lt;p&gt;这些，是需要花大量的时间去了解。&lt;/p&gt;&lt;p&gt;全部都是实在的经验积累，没有捷径。&lt;/p&gt;&lt;p&gt;都是.NET语言，C# 跟 VB.Net的差别在哪里？对于ED，他们偶尔也会对这样的问题感兴趣，然后，他们会去看介绍，看比较文章。。。。但其实，这事完全是木有用的。&lt;/p&gt;&lt;p&gt;他们看了别人的介绍，以为自己懂的，但实际上，他们只是在复读而已，完全木有懂。&lt;/p&gt;&lt;p&gt;作为一个ED，要了解C#跟VB.Net的差别在哪里，最好的方式，就是花时间去把两种语言都学了。用这两种语言分别去写个几万行程序，然后就懂了。&lt;/p&gt;&lt;p&gt;当某天ED成为Hacker的时候，那就反倒可以去看各种介绍，看一眼，然后瞬间就可以悟了。&lt;/p&gt;&lt;p&gt;这也就是为什么很牛程序员学习新语言可以那么快，因为有太多的知识可以复用；而这些知识的积累，必然是需要通过在实际中，无数行的实际编码，无数篇的资料阅读中得来的。&lt;/p&gt;&lt;p&gt;没有捷径。&lt;/p&gt;&lt;p&gt;很多初学者，或者说，编程的伪爱好者，他们，会热衷于去四处请教大师，下载各种经典书籍，企图读一本编程圣经，然后一夜脱胎换骨。&lt;/p&gt;&lt;p&gt;这是，不可能的。&lt;/p&gt;&lt;p&gt;这种伪爱好者，永远不可能成事；在学习的过程中，抱着去&amp;#8220;走捷径&amp;#8221;的心态，本身就已经是入了歧途；最终会花更多的时间。&lt;/p&gt;&lt;p&gt;原来Ruby / 现在 Python的一个光头大牛Zed A. Shaw，为了表达&amp;#8220;没有捷径&amp;#8221;这样的观点，特意写了本《Learn Python The Hard Way》：&lt;br /&gt;&lt;a href="http://learnpythonthehardway.org/"&gt;http://learnpythonthehardway.org/&lt;/a&gt;&lt;/p&gt;&lt;p&gt;甚至有一个系列：&lt;a href="http://learncodethehardway.org/"&gt;http://learncodethehardway.org/&lt;/a&gt;&lt;/p&gt;&lt;p&gt;从长远来看：The Hard Way Is Easier。&lt;/p&gt;&lt;p&gt;我完全同意。&lt;/p&gt;&lt;p&gt;作业：&lt;/p&gt;&lt;p&gt;1. 列举10个Python Web框架&lt;/p&gt;&lt;p&gt;2. Python有多少种不同的解释器？&lt;/p&gt;&lt;p&gt;3. Perl 跟 Python 有什么不同？&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;请看这个帖子：&amp;nbsp;&lt;a href="http://blog.csdn.net/hu_zhenghui/article/details/7184799"&gt;http://blog.csdn.net/hu_zhenghui/article/details/7184799&lt;/a&gt;&lt;/p&gt;&lt;p&gt;快速浏览即可，无需细读；浏览过后再继续往下看。&lt;/p&gt;&lt;p&gt;读后的感觉是不是：&lt;/p&gt;&lt;p&gt;&amp;#8220;虽然不知道在说什么，但是看起来很厉害的样子！&amp;#8221;&lt;/p&gt;&lt;p&gt;整篇文章的关键是在这句：&lt;/p&gt;&lt;p&gt;&amp;#8220;作者胡某某。曾任完美时空（现更名为完美世界）顾问，承担互联网方面的部分管理工作。现在主要精力研究互联网产品设计，是Axure授权的高级咨询顾问和高级培训讲师。&amp;#8221;&lt;/p&gt;&lt;p&gt;这也就是，我在第一课中提到的&amp;#8220;啥事不做，整天四处布道，名头都很响亮，如XX金牌讲师&amp;#8221;，&amp;#8220;Evangelist本身的技术，很多是很差的；就好像推销员本身，是不会做产品开发、不懂技术的。他们仅仅是会宣传、鼓吹新技术而已&amp;#8221;。&lt;/p&gt;&lt;p&gt;碰巧今天看到这个非常有代表性的帖子；整个帖子看下来，作者毫无海量数据处理实际开发经验，纯粹堆砌这些流行技术名词而已。他没有用过这些技术，随便乱丢技术名词，整篇似是而非，必然的结果就是：&amp;#8220;虽然不知道在说什么，但是看起来很厉害的样子！&amp;#8221;&lt;/p&gt;&lt;p&gt;学习技术的人，如果受了这种&amp;#8220;看起来很厉害的样子！&amp;#8221;的蒙骗，会走很多很多弯路。&lt;/p&gt;&lt;p&gt;那么，如何识别&amp;#8220;看起来很厉害&amp;#8221;跟&amp;#8220;真的很厉害&amp;#8221;？&lt;/p&gt;&lt;p&gt;就好像，CSDN虽然有些忽悠人的文章，但也是有些好的文章在里面，如何辨别？&lt;/p&gt;&lt;p&gt;&lt;strong&gt;1. 看得多了，自然会分辨。&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;研发知识的最好来源之一是技术博客，就我自己而言，看了博客园自创办伊始前5年的所有首页文章；外加常年订阅400+博客，twitter fo 400余人等。&lt;/p&gt;&lt;p&gt;我这么做，主要是因为看得快；没有&amp;#8220;看不过来&amp;#8221;的问题；但实际上是个很笨的办法。&lt;/p&gt;&lt;p&gt;要保持最新技术的了解，确实是需要看很多blog；除此之外，我想不出别的途径；但这并非必要。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;2. 看书&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;多看，最大的好处是了解最新技术，而且这是很土的方法。很多时候，并不需要了解很多&amp;#8220;最新技术&amp;#8221;；很多&amp;#8220;最新技术&amp;#8221;都是属于第一课中所讲的&amp;#8220;封装技术&amp;#8221;，不了解，也完全没有关系。&lt;/p&gt;&lt;p&gt;计算机的经典好书并不多，好书是公认、经得起时间考验的。&lt;/p&gt;&lt;p&gt;看完这个豆列也就差不多了：&lt;a href="http://book.douban.com/doulist/995755/"&gt;http://book.douban.com/doulist/995755/&lt;/a&gt;&lt;/p&gt;&lt;p&gt;完全可以不去理解&amp;#8220;最新&amp;#8221;的浮躁，去上面的豆列挑几本看，仔细的看，就可以脱胎换骨了。&lt;/p&gt;&lt;p&gt;就我自己而言，对我技术影响最大的一本书倒不在上面豆列的20本书中，而是：&lt;a href="http://book.douban.com/subject/1467587/"&gt;http://book.douban.com/subject/1467587/&lt;/a&gt;&lt;/p&gt;&lt;p&gt;经典书，是必须看，并且反复看的；如果说有什么&amp;#8220;捷径&amp;#8221;的话，看经典书就是最快的捷径了。&lt;/p&gt;&lt;p&gt;这些经典书中的思想，是永远不会过时的；任何时候看，都不会太晚。&lt;/p&gt;&lt;p&gt;给ED看的书也有经典：&lt;a href="http://book.douban.com/subject/1229954/"&gt;http://book.douban.com/subject/1229954/&lt;/a&gt;&lt;/p&gt;&lt;p&gt;首先，这是本好书；而且这本500多页书的传奇在于它讲了无数企业开发的模式，但其中的一页半讲述的：Active Record Pattern影响了过去5年多6年的Web开发潮流。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;3. 写代码 + 看代码&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;学习编程，是一定要去编程的。&lt;/p&gt;&lt;p&gt;书、资料再好，光看不练；也很容易把自己看成傻子。&lt;/p&gt;&lt;p&gt;在实际项目中写代码；然后看别人是怎么做的。&lt;/p&gt;&lt;p&gt;别人，指的往往是开源项目；而不是Google搜来的某个不知名博客中贴的代码。哪个开源项目比较厉害，同样是有目共睹的。&lt;/p&gt;&lt;p&gt;做Web开发，几乎所有人都会去造ORM的轮子，没事，就去造一个；然后比较自己的版本，跟优秀的开源ORM在API风格、架构设计、实现细节上，有何不同。&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;作者给的作业：&lt;/p&gt;&lt;p&gt;1. 找出一篇看上去很厉害的文章。&lt;/p&gt;&lt;p&gt;2. 找一本书，开始看，作为期中考书目。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;【51CTO独家特稿】承接上文，12306的案例是蛮不错的题材；看过咨询师&amp;#8220;很厉害的样子&amp;#8221;，那么，究竟要如何做好 「海量事务高速处理系统」 这个方案？&lt;/p&gt;&lt;p&gt;&amp;#8220;Hacker&amp;#8221;提出了方案：caoz，出自百度的超低调牛人：&lt;a href="http://hi.baidu.com/caoz/blog/item/f4f1d7caee09b558f21fe780.html"&gt;http://hi.baidu.com/caoz/blog/item/f4f1d7caee09b558f21fe780.html&lt;/a&gt;&lt;/p&gt;&lt;p&gt;云风，原网易杭州研究中心总监：&lt;a href="http://blog.codingnow.com/2012/01/ticket_queue.html"&gt;http://blog.codingnow.com/2012/01/ticket_queue.html&lt;/a&gt;&lt;/p&gt;&lt;p&gt;同样的，也有另外一些&amp;#8220;ED&amp;#8221;在讨论方案：&lt;/p&gt;&lt;p&gt;林仕鼎，百度首席架构师，曾任微软亚洲研究院研究员：&lt;/p&gt;&lt;p&gt;&lt;a href="http://qing.weibo.com/2244218960/85c41050330009xm.html"&gt;http://qing.weibo.com/2244218960/85c41050330009xm.html&lt;/a&gt;&lt;br /&gt;&lt;a href="http://weibo.com/2244218960/y0l4S7Y1d"&gt;http://weibo.com/2244218960/y0l4S7Y1d&lt;/a&gt;&lt;/p&gt;&lt;p&gt;白硕sse，上海证券交易所总工程师：&lt;br /&gt;&lt;a href="http://weibo.com/1922397344/y0jMo9IaD"&gt;http://weibo.com/1922397344/y0jMo9IaD&lt;/a&gt;&lt;br /&gt;&lt;a href="http://weibo.com/1922397344/y0jP6jNRB"&gt;http://weibo.com/1922397344/y0jP6jNRB&lt;/a&gt;&lt;br /&gt;&lt;a href="http://weibo.com/1922397344/y0jUy2rkf"&gt;http://weibo.com/1922397344/y0jUy2rkf&lt;/a&gt;&lt;/p&gt;&lt;p&gt;且不论&amp;#8220;Hacker&amp;#8221;跟&amp;#8220;ED&amp;#8221;谁更加牛，从他们的解决问题的手法、角度上看就非常不同。&lt;/p&gt;&lt;p&gt;&amp;#8220;Hacker&amp;#8221;所追求的是解决问题，只要是问题被解决，怎么解决的无所谓；并发流量太大，系统处理不过来；caoz / 云风两种的方案，实质上都是直接去处理源头 - 避免并发。&lt;/p&gt;&lt;p&gt;caoz把高并发的请求直接分流去非主业务服务器，主业务服务器无需面临高并发；云凤则提出排队系统，避免高并发的出现。&lt;/p&gt;&lt;p&gt;而林仕鼎、白硕则是正儿八经的去讨论在有这样高并发的前提下，要怎么处理。&lt;/p&gt;&lt;p&gt;哥伦布的鸡蛋。&lt;/p&gt;&lt;p&gt;能够用手去扶住鸡蛋，&amp;#8220;Hacker&amp;#8221;绝对不会犹豫；而&amp;#8220;ED&amp;#8221;则努力的去把鸡蛋竖起来。&lt;/p&gt;&lt;p&gt;注意，牛&amp;#8220;ED&amp;#8221;未必就不懂得可以用手。&lt;/p&gt;&lt;p&gt;这样&amp;#8220;Hacker&amp;#8221;精神，在云风的blog上，还有另一个体现：屏蔽垃圾评论的验证码。&lt;/p&gt;&lt;p&gt;博客有很多垃圾评论，需要屏蔽，有很多很多种方式，各种神奇的验证码，叶贝斯规则过滤等等。&lt;/p&gt;&lt;p&gt;&amp;#8220;ED&amp;#8221;可以设计出来很多方案，并实现。&lt;/p&gt;&lt;p&gt;云风肿么做呢？&lt;/p&gt;&lt;p&gt;他在评论发表的时候，增加了一个项目：为了验证您是人类，请将六加一的结果（阿拉伯数字七）填写在下面&lt;/p&gt;&lt;p&gt;&amp;#8220;只要能解决问题，就采用最简单的设计。&amp;#8221;&lt;/p&gt;&lt;p&gt;这个验证码插件是我自己写的，只有一行 perl 代码。就是判断输入是不是 '7' 。&lt;/p&gt;&lt;p&gt;结果它很管用。从后台 log 看，拦截了几万条 spam 。&lt;a href="http://blog.codingnow.com/2012/01/dev_note_7.html#comment-42161"&gt;http://blog.codingnow.com/2012/01/dev_note_7.html#comment-42161&lt;/a&gt;&lt;/p&gt;&lt;p&gt;注意，牛的&amp;#8220;Hacker&amp;#8221;未必就不懂得做出庞大架构并实现。&lt;/p&gt;&lt;p&gt;要如何做好「海量事务高速处理系统」这个方案&amp;#8221;本身就可能是个伪命题，「海量事务高速处理系统」这个需求本身可能根本就不存在。&lt;/p&gt;&lt;p&gt;作业：&lt;/p&gt;&lt;p&gt;1. 林仕鼎是百度首席架构师吗？&lt;/p&gt;&lt;p&gt;2. 看完caoz所有的blog。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;在几乎所有的web应用中，数据库都是核心的一环。&lt;/p&gt;&lt;p&gt;Web应用往往都是&amp;#8220;Database driven&amp;#8221;，业务、数据都是由数据库完成，而前端页面仅仅是演示、修改数据的一个&amp;#8220;壳&amp;#8221;。&lt;/p&gt;&lt;p&gt;因此很多web框架，都会标榜自己能够兼容多少多少数据库，做CRUD多么多么容易。&lt;/p&gt;&lt;p&gt;一般上，提到数据库的时候，指的都是关系型数据库；但关系型数据库并非唯一的一种数据库类型。&lt;/p&gt;&lt;p&gt;关系型数据库，一开始便是设计为通用，并有ACID支持的。&lt;/p&gt;&lt;p&gt;Atomicity 原子性、 Consistency 一致性、Isolation 隔绝性、Durability 持久性&lt;/p&gt;&lt;p&gt;杀手欧阳盆栽说：&amp;#8220;每件事都有它的代价&amp;#8221;。上述四个特性，都是有代价的。&lt;/p&gt;&lt;p&gt;对于严谨的商业应用，如银行、交易系统；为求业务的安全，他们不得不，或者说，能够并且愿意付出这些代价。&lt;/p&gt;&lt;p&gt;回到12306，后端数据库传说使用的是Oracle，而站出来说吐槽12306的行家往往都会提到 redis \ mysql 这样的替代。&lt;/p&gt;&lt;p&gt;有些菜鸟&amp;#8220;ED&amp;#8221;看到这些吐槽就出来喷了，说这些行家不懂神马业务安全性的重要，这帮做互联网的弱爆了，票务是必须使用 Oracle才能搞定云云。&lt;/p&gt;&lt;p&gt;好像还有人专门去喷了Fenng，这实在是太讽刺了。Fenng实际上是Orcale ACE Director &lt;a href="http://www.hudong.com/wiki/%E5%86%AF%E5%A4%A7%E8%BE%89"&gt;http://www.hudong.com/wiki/%E5%86%AF%E5%A4%A7%E8%BE%89&lt;/a&gt;，国内屈指可数的Oracle专家。&lt;/p&gt;&lt;p&gt;很多人，特别是弱&amp;#8220;ED&amp;#8221;、&amp;#8220;专家教授&amp;#8221;，沉寂在自己所在的领域，然后就以为&amp;#8220;悟&amp;#8221;了；实际上，仅是把自己变成了井底之蛙。&lt;/p&gt;&lt;p&gt;知识的广博、全面性非常重要。&lt;/p&gt;&lt;p&gt;在某个领域，通用的东西成熟之后，往往就会有专用的解决方案出现。而专用的解决方案多了之后，又会有新的通用解决方案出现。&lt;/p&gt;&lt;p&gt;天下大势，分久必合，合久必分。&lt;/p&gt;&lt;p&gt;计算机，最早有很多专用系统，如王安打字机；个人电脑通用之后，这些专用设备就湮灭了；而iPad、手机的涌现，则又是专用系统。&lt;/p&gt;&lt;p&gt;是的，传统上需要去购买 Orcale、DB2 等巨贵无比的数据库系统，去满足业务需求；不是因为它们把问题解决到了极致，而是因为没有别的选择。时代已经变了，井底之蛙若把Oracle当成是王道，那只能被时代淘汰。&lt;/p&gt;&lt;p&gt;关系型数据库作为通用解决方案，是非常非常好的；它是一把神刀。&lt;/p&gt;&lt;p&gt;但是，它有以下问题：&lt;/p&gt;&lt;p&gt;===== ED总是要写烂SQL ====&lt;/p&gt;&lt;p&gt;首先. 还是那句话，有的人纵然神刀在手，亦无法成为刀中之神。关系型数据库提供的SQL能力，是高度抽象的，封装了无数层的。写SQL的人，太多太多根本不了解SQL背后所执行的事情；烂&amp;#8220;ED&amp;#8221;都是如此。&lt;/p&gt;&lt;p&gt;这甚至造就了一个职业：DBA。DBA去负责数据库微调、优化，听起来很高级，但实质上，就是给滥用SQL的&amp;#8220;ED&amp;#8221;擦屁股而已。&lt;/p&gt;&lt;p&gt;对于庞大的企业来说，管理者是知道大部分ED都弱爆了，他不期望也不需要ED去了解数据库，他只需要ED去完成最基本的业务功能，然后让DBA去给ED擦屁股。&lt;/p&gt;&lt;p&gt;大部分的ED，并没有意识到这一点；他们拼命去追求方便快捷的&amp;#8220;搞定&amp;#8221;；滥用SQL的各种高级功能；甚至，他们把分享SQL的复杂使用当成是乐事。&lt;/p&gt;&lt;p&gt;ED所努力的，是把自己变笨，把活尽可能的都交给神奇的数据库去解决；数据库怎么解决的，他们不关心；这实质上，是在削弱自己工作的技术含量，自我贬值而已。&lt;/p&gt;&lt;p&gt;工程师如果能够把数据库给用好了，哪里还有DBA什么事？&lt;/p&gt;&lt;p&gt;DBA所谓的数据库优化，往往就是把工程师不负责任写下的2B SQL查询找出来，然后改写为文艺方式罢了。&lt;/p&gt;&lt;p&gt;不要滥用数据库，一点都不难。&lt;/p&gt;&lt;p&gt;===== 通用数据库性能有极限 =====&lt;/p&gt;&lt;p&gt;其次，关系型数据库作为通用解决方案，它提供了太多的东西，它做了太多的事，而所有的事情，都有它的代价，直接而言，就是牺牲性能了。&lt;/p&gt;&lt;p&gt;所以，DBA的另一个职责，则是把数据库的各种参数调配好，让其能够发挥最高的性能。&lt;/p&gt;&lt;p&gt;从这个意义上去说，DBA的工作就不仅仅是给ED擦屁股了。&lt;/p&gt;&lt;p&gt;但，这样的微调，是有极限的。DBA拚了命去把鸡蛋竖立起来，考虑了桌面摩擦、空气流动、手指颤抖等等因素，鸡蛋虽然可以竖立一会，但终究还是会倒下去；这也就是微调的极限。&lt;/p&gt;&lt;p&gt;在某些场景下，是可以用手的：把业务中没有用到的数据库功能都去掉；甚至，去掉完整的ACID支持。&lt;/p&gt;&lt;p&gt;这样一来，数据库的性能就可以有数量级的改善了。&lt;/p&gt;&lt;p&gt;===== 关键在于灵活性 ====&lt;/p&gt;&lt;p&gt;最后，上面两点，其实都是跟性能相关的；关系型数据库即便作为通用方案，它的性能有极限，但也能够满足绝大多数应用场景了。关系型数据库的软肋，是在灵活性上。&lt;/p&gt;&lt;p&gt;数据库有表、而表有结构；而表的结构，在应用上线之后，很难修改。&lt;/p&gt;&lt;p&gt;这同样造就了一些专业学问：严密的业务分析、设计数据库结构、如何在数据库上线之后修改结构等等。&lt;/p&gt;&lt;p&gt;这些问题或者说学问之所以存在，是植根于关系型数据库表结构不灵活的前提之上。&lt;/p&gt;&lt;p&gt;再次&amp;#8221;Think out of the box&amp;#8220;，如果数据库可以做到灵活、随时修改的表结构呢？&lt;/p&gt;&lt;p&gt;====== NoSQL ======&lt;/p&gt;&lt;p&gt;关系型数据库的三个问题，被NoSQL全部解决了。&lt;/p&gt;&lt;p&gt;（同样的，所有事情都有它的代价；NoSQL在解决SQL固有问题的同时，也引入了新的问题；另一方面，NoSQL解决的也不仅仅是SQL的这三个问题。）&lt;/p&gt;&lt;p&gt;ED要写烂SQL？没有关系，彻底不让他们写SQL好了。&lt;/p&gt;&lt;p&gt;数据库支持功能太多？砍功能还不容易么？&lt;/p&gt;&lt;p&gt;Schema不灵活？那就schema-less好了。&lt;/p&gt;&lt;p&gt;目前，NoSQL的实现方案很多，MongoDB、Redis、Carssendra等等等等；每一个都可以非常不同，是专用解决方案：有自己独有的特性，去解决特定场景的特定问题。&lt;/p&gt;&lt;p&gt;（当然，像MongoDB，已经很有NoSQL通用解决方案的意味了。）&lt;/p&gt;&lt;p&gt;普通程序员用SQL，文艺程序员用NoSQL，2B程序员把NoSQL当SQL用。&lt;/p&gt;&lt;p&gt;普通程序员在从SQL切换去NoSQL时，会受固有的SQL知识限制，总有把NoSQL当成SQL去用的冲动，但这是非常2B的行为。&lt;/p&gt;&lt;p&gt;从微观的角度讲，原来SQL查询中所支持的各种神奇joining / groupby都不见了；拼命的想要去找在NoSQL数据库环境下同样的神奇工具。&lt;/p&gt;&lt;p&gt;这彻底违背了使用NoSQL的初衷：为了就是不让你滥用SQL的这些神奇功能。&lt;/p&gt;&lt;p&gt;滥用SQL会造成严重的性能问题，而在性能问题浮现之后，需要耗费更大的力气去纠正。&lt;/p&gt;&lt;p&gt;是的，信用卡透支购物很方便；但付账单的时候就傻逼了；所以，换成无法透支的借记卡。&lt;/p&gt;&lt;p&gt;固然没有了透支的便利，会有不方便，但彻底杜绝了还不起账单，被收取高额利息的问题。&lt;/p&gt;&lt;p&gt;要透支的便利？ED，请先去掌握好理财技能，彻底了解透支的影响，然后我们再来谈便利。&lt;/p&gt;&lt;p&gt;从宏观的角度讲，会有人企图去给NoSQL做封装，让NoSQL表现得跟SQL一样；甚至，去把NoSQL去掉的那些SQL功能加回去。&lt;/p&gt;&lt;p&gt;SQL已经是一个非常非常成熟的方案，它所能够解决的问题范畴里面，几乎没有办法做得比SQL更好。&lt;/p&gt;&lt;p&gt;在NoSQL的基础上，去试图模拟SQL，只能成为SQL的蹩脚模拟；还不如直接用回SQL。&lt;/p&gt;&lt;p&gt;在网路编程里面也有类似的例子，TCP跟UDP。可以把SQL看成是TCP，它是可靠、神奇的。UDP虽然不可靠，但是会比TCP更快。要做视频、语音通讯，UDP是更好的选择。但要去做&amp;#8220;不丢包、不失帧&amp;#8221;的可靠视频通讯，选择在UDP的基础上添加确认、重发机制模拟TCP，那就是2B了。不是天才，没法做得比TCP更好，直接用TCP就好。&lt;/p&gt;&lt;p&gt;作业：&lt;br /&gt;1. NoSQL的方案，如MongoDB还解决了SQL的什么问题？&lt;/p&gt;&lt;p&gt;2. NoSQL的应用场景有啥米？&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;设计模式，应该是很多ED心目中牛B的编程方式。&lt;/p&gt;&lt;p&gt;上回说到ED的好书POEE，实际上便是一本专门讲企业开发中使用的设计模式中的书。&lt;/p&gt;&lt;p&gt;设计模式，并不多，基本上看完GoF的这边《Design Pattern》便可以有足够了解了。&lt;/p&gt;&lt;p&gt;而实际开发中常用的设计模式更是屈指可数，Singleton，Factory，Facade，Active Record、Provider等等。&lt;/p&gt;&lt;p&gt;就那么几个，花花功夫，仔细了解一下这几个，然后在实际编码中应用一下，便可以算是掌握了。&lt;/p&gt;&lt;p&gt;设计模式，并不难。&lt;/p&gt;&lt;p&gt;它是开发中非常必要的知识，实际上，是非常基础的知识，并不牛B。&lt;/p&gt;&lt;p&gt;开发的时候，需要时刻明确自己的目标：解决问题。&lt;/p&gt;&lt;p&gt;解决问题才是最重要的。&lt;/p&gt;&lt;p&gt;设计模式的存在，是为了更好的维护、管理代码，或者是为了扩展性；绝对不可以为了设计模式而模式。&lt;/p&gt;&lt;p&gt;在Java程序中，为了模式而模式的现象蛮普遍的。&lt;/p&gt;&lt;p&gt;我猜想这是因为Java是一门工业语言，有大量的ED使用的缘故。&lt;/p&gt;&lt;p&gt;ED把设计模式的使用，当成是一种可以炫耀的编程技巧，或者说，他们遵从的编码规范中，要求他们去使用某某设计模式。&lt;/p&gt;&lt;p&gt;至于为什么要使用设计模式，最常见的理由便是：为了将来可以XX，或者YY。&lt;/p&gt;&lt;p&gt;程序开发中，有一句名言：&amp;#8220;Pre-mature optimization is the root of all evil&amp;#8221;。&lt;/p&gt;&lt;p&gt;过早优化，是万恶之源。&lt;/p&gt;&lt;p&gt;非常多的情况下，将来预想中的XX或者YY；并不会发生。大部分代码，写了之后就会被丢弃掉，再也不会有人去维护。&lt;/p&gt;&lt;p&gt;当XX或者YY发生的时候，往往，都是会推倒重来。&lt;/p&gt;&lt;p&gt;除非你很牛B，只有牛到一定程度，才有可能对将来可能发生的情况做好合理的预测，并预留出改善、调整的空间。&lt;/p&gt;&lt;p&gt;但非常讽刺的是，为将来做设计的最好方法就是：什么都不做。&lt;/p&gt;&lt;p&gt;只有空白，才能够留下最大的发挥空间。&lt;/p&gt;&lt;p&gt;现在为将来可能发生的情况，做了编码，任何一行编码，都是很可能是在为将来添加限制、制造麻烦。&lt;/p&gt;&lt;p&gt;现在写下去的代码，将来，都是要被删掉的；能够不写，就不写。&lt;/p&gt;&lt;p&gt;在任何时候，都应该保持代码简洁。&lt;/p&gt;&lt;p&gt;函数，尽可能的短；当一个函数的长度，超过一个屏幕的时候，便应该考虑重构、拆分。&lt;/p&gt;&lt;p&gt;牛B的程序，都应该是简单、易懂的；采用大量的设计模式，复杂得让人无法直接看懂，或许有它的意义以及应用场景，但这绝对不是编程功力牛B的表现。&lt;/p&gt;&lt;p&gt;打个比方，设计模式就是武术招式。&lt;/p&gt;&lt;p&gt;学徒，必然需要熟悉什么&amp;#8220;有风来仪&amp;#8221;或者&amp;#8220;屁股朝后平沙落雁式&amp;#8221;。&lt;/p&gt;&lt;p&gt;但更高的境界是：无招胜有招。&lt;/p&gt;&lt;p&gt;简单、直接的把代码搞定。&lt;/p&gt;&lt;p&gt;Python大牛沈崴有云：&amp;#8220;得道的程序员，既不封装，也没有重复代码。&amp;#8221;&lt;a href="http://eishn.blog.163.com/blog/static/6523182010102342531684/"&gt;http://eishn.blog.163.com/blog/static/6523182010102342531684/&lt;/a&gt;&lt;/p&gt;&lt;p&gt;作业：&lt;/p&gt;&lt;p&gt;1. 使用一种编译语言实现 Singleton 模式&lt;/p&gt;&lt;p&gt;2. 使用一种动态语言实现 Singleton 模式&lt;/p&gt;&lt;p&gt;3. 说说对 Provider 模式的理解。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;【51CTO独家特稿】设计模式再&amp;#8220;高级&amp;#8221;一点，便是所谓的&amp;#8220;框架&amp;#8221;了。&lt;/p&gt;&lt;p&gt;从事Web开发，一般都会接触到MVC框架这个概念。&lt;/p&gt;&lt;p&gt;M：也就是Model，直接跟网站数据库相关。&lt;/p&gt;&lt;p&gt;V：也就是View，是网页的模版，跟显示数据相关。&lt;/p&gt;&lt;p&gt;C：则是Controller，相当于网站的业务逻辑。&lt;/p&gt;&lt;p&gt;MVC也不仅仅是应用于网站开发，它的概念实际上植根于桌面软件，并且在手机软件开发上也有应用。&lt;/p&gt;&lt;p&gt;MVC本身是一个设计模式，是一个被验证过的，可以用来很好归纳、管理代码的软件开发方式。&lt;/p&gt;&lt;p&gt;基于这样的设计模式，提供了很多相关的类库实现，则&amp;#8220;设计模式&amp;#8221;升级为&amp;#8220;框架&amp;#8221;。&lt;/p&gt;&lt;p&gt;MVC的任何一个方面，扩展出去讲，都可以讲上几天几夜。&lt;/p&gt;&lt;p&gt;今天只讲V。&lt;/p&gt;&lt;p&gt;传统的ASP / PHP网站开发，V是很混乱的。&lt;/p&gt;&lt;p&gt;默认只有一种文件，html与业务逻辑代码混杂在同一个文件；相当难以维护。&lt;/p&gt;&lt;p&gt;ASP.NET相对于asp做出了很大改进，提出了code-behine的概念：默认将html的模版代码，以及c#或者vb.net的逻辑代码切分到两个不同的文件。&lt;/p&gt;&lt;p&gt;这样的方式算是有很大进步。&lt;/p&gt;&lt;p&gt;微软平台上做开发是比较苦逼的，微软掌控了整个开发平台的前进速度。&lt;/p&gt;&lt;p&gt;asp跟PHP在开始的时候，是相似的技术。有类似的便利，以及类似的麻烦。&lt;/p&gt;&lt;p&gt;微软推出了.net，推广了code-behind的模式；然后，所有的微软程序员都超着微软指定的这个方向去迈进。&lt;/p&gt;&lt;p&gt;asp被抛弃了，自从ASP.NET诞生之后，就不再有任何改进。&lt;/p&gt;&lt;p&gt;而PHP，在开源世界中，则不断的得到各式各样的改进。&lt;/p&gt;&lt;p&gt;各种模版引擎层出不穷；不仅可以实现code-behind这样简单的模版、业务代码分割；很多还直接引入了MVC的概念；实现了三层的分割。&lt;/p&gt;&lt;p&gt;而ASP.NET，则长期止步于web form的code-behind，在开源世界中的MVC方案大放光彩若干年后，才推出 ASP.NET MVC。&lt;/p&gt;&lt;p&gt;模版技术，最初的目的就是要把业务代码，也就是说，把获得数据的代码跟html分割。&lt;/p&gt;&lt;p&gt;在模版实现上，因此涌现了不少不同的设计哲学。&lt;/p&gt;&lt;p&gt;Python的Django框架中的模版，是一种典型。&lt;/p&gt;&lt;p&gt;它彻底的禁止程序员在模版中嵌入任何代码；模版中，只可以出现html；以及一些跟业务逻辑无关的控制标签，如：&lt;br /&gt;{% If XXXX %} foo {% else %} bar {% end %} &lt;/p&gt;&lt;p&gt;条件XXXX，必须是一个数据值，不可以是一个复杂表达式、不可以包涵函数调用等等。&lt;/p&gt;&lt;p&gt;模版中，也不可以声明任何新的变量，下面的做法是被禁止的：&lt;br /&gt;{% set i = 0 %}&amp;nbsp; &lt;br /&gt;{% foreach item in items %}&amp;nbsp; &lt;br /&gt;&amp;nbsp;{% i += 1%}&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;lt;div&amp;gt;&amp;nbsp; &lt;br /&gt;&amp;nbsp; {{ item }}&amp;nbsp; &lt;br /&gt;&amp;nbsp; {% if i mod 2 == 0 %}&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;lt;hr /&amp;gt;&amp;nbsp; &lt;br /&gt;&amp;nbsp; {% end %}&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;lt;/div&amp;gt;&amp;nbsp; &lt;br /&gt;{% next %} &lt;/p&gt;&lt;p&gt;Django的模版，从技术上彻底禁止程序员添加任何逻辑，强迫程序员必须在controller中去写各种逻辑，以确保模版内容的纯洁干净。&lt;/p&gt;&lt;p&gt;所以Django的模版，一般都非常简单，有很好的移植性，并且可以让网页设计人员直接编辑。&lt;/p&gt;&lt;p&gt;ASP.NET则是另一种典型；虽然有了code-behind，但是它没有对前端代码，以及后端代码做任何限制。&lt;/p&gt;&lt;p&gt;在前端aspx页面中，可以嵌入任意的逻辑代码，而code-behind的code，为空白；这种伪&amp;#8220;code-behind&amp;#8221;的方式，跟原来的asp没啥区别。&lt;/p&gt;&lt;p&gt;ASP.NET从框架本身，并不阻止程序员去做这样的事情，实际上，它还标榜它这样的特性：方便原有的asp项目直接升级到.NET的平台上。&lt;/p&gt;&lt;p&gt;也有另外一种奇葩的做法，前端aspx页面保持空白，然后在code-behind的code中去拼接所有的html。这样的方式，ASP.NET框架本身也不禁止。&lt;/p&gt;&lt;p&gt;只要ASP.NET程序员喜欢，没有什么不可以的。&lt;/p&gt;&lt;p&gt;ASP.NET把对模版使用方式的选择权留给了程序员，如果程序员自律，他们可以按Django模版那样的方式去使用模版，并拥有Django一样的优点；如果程序员自律？！&lt;/p&gt;&lt;p&gt;在某些可以通过嵌入代码去快速处理的场景，ASP.NET的模版也保留了程序员去hack的能力。&lt;/p&gt;&lt;p&gt;还有一些模版技术，则是折衷的（如tornado的模版）：允许嵌入单行代码，如声明变量，调用函数等等；但是不允许整块、整块的业务代码出现模版中。&lt;/p&gt;&lt;p&gt;上述三种模版设计哲学，各有它们的道理，以及应用场景。&lt;/p&gt;&lt;p&gt;需要根据具体的业务、应用场景，才能说其中哪种比较合适。&lt;/p&gt;&lt;p&gt;开发人员的能力也是直接相关的，如果团队中，普遍不自律；缺乏将业务、模版代码分割、以提高代码可维护性的意识，那么Django的做法是最好的，它直接禁止去滥用模版，强迫他们去使用更好的开发风格；即便在某些场景下会更麻烦。&lt;/p&gt;&lt;p&gt;武断的认为任何一种模版设计哲学是&amp;#8220;最佳&amp;#8221;的想法是极其肤浅的。&lt;/p&gt;&lt;p&gt;各种成熟的模版技术，一般也都会有包括以下特性：&lt;/p&gt;&lt;p&gt;1. 嵌入&lt;/p&gt;&lt;p&gt;也就是说，编写各种可以复用的小模版块，然后供多个不同地方调用；比方说，用户头像（甚至名片）的显示。&lt;/p&gt;&lt;p&gt;具体页面不需要重复编写这些重复的模块。&lt;/p&gt;&lt;p&gt;并且，这些模块需要调整时，只需要修改一个地方，便可以在所有地方生效。&lt;/p&gt;&lt;p&gt;2. 继承&lt;/p&gt;&lt;p&gt;能够编写一些基础模版，定义常见的页面结构。&lt;/p&gt;&lt;p&gt;具体页面继承这些基础模版，便不需要重复编写那些结构代码。&lt;/p&gt;&lt;p&gt;同样的，当页面结构需要调整时，也是修改一处，所有生效。&lt;/p&gt;&lt;p&gt;3. i18n&lt;/p&gt;&lt;p&gt;网页模版的国际化支持是一个模版引擎是否成熟的表现。&lt;/p&gt;&lt;p&gt;如果没有，当网站需要同时提供多种不同语言支持的时候，会很麻烦。&lt;/p&gt;&lt;p&gt;成熟的模版，都会提供内置的支持。&lt;/p&gt;&lt;p&gt;因为网页模版实现实在是太多了，大家功能也都差不多，那么性能，也就成为了相当重要的比较指标。&lt;/p&gt;&lt;p&gt;有的模版，能够&amp;#8220;编译&amp;#8220;，渲染起来快些。&lt;/p&gt;&lt;p&gt;一般可以简单认为，功能越多的模版，性能会约低。有的模版，甚至将i18n的支持变成可配置的，不需要的时候就可以关闭，以提高性能。&lt;/p&gt;&lt;p&gt;也有的模版认为，写 {% %} &amp;lt;%%&amp;gt; {{}} 这样的符号太麻烦了，可以直接忽略，它可以自动聪明的识别 html，以及模版控制代码。简单的说，就是以极其华丽的方式，去方面程序员少打几个字符。&lt;/p&gt;&lt;p&gt;还有的模版，在实现嵌入功能的时候，还可以选择所依赖的的css / js文件。&lt;/p&gt;&lt;p&gt;比方说，要显示用户的名片，需要引入 namecard.css；那么，可以在 namecard的模块文件中指定这个依赖，然后模版渲染的时候，自动把这个css的引用，放在html的头部。&lt;/p&gt;&lt;p&gt;直接在模块文件中写 namecard.css 的引用是很傻的，因为模块可以在模版中引用多次。重复引用同一个css文件是没有道理的。&lt;/p&gt;&lt;p&gt;种种模版功能细节，实际上，都是可以在没有模版支持的框架中去实现。&lt;/p&gt;&lt;p&gt;想想PHP，它本来是非常简单的，默认只能够在同一个文件中混杂逻辑与代码。&lt;/p&gt;&lt;p&gt;但一旦程序员有了追求，它也可以有模版实现。&lt;/p&gt;&lt;p&gt;模版不支持 i18n，程序员一般也是有办法在现有模版实现中添加相应的支持的。&lt;/p&gt;&lt;p&gt;并不复杂，关键是看程序员的态度；看程序员是否有把事情做得更好、更优雅的态度。&lt;/p&gt;&lt;p&gt;一般情况下，程序员选择去实现更多的模版功能的时候，必须先看看别人是怎么做的。比方说，如果完全不知道什么是gettext就去自行实现模版的 i18n 功能，是非常2B的。&lt;/p&gt;&lt;p&gt;绝大多数情况下，程序员面临的问题，都不是自己独有的，一定是别人已经解决过的问题。&lt;/p&gt;&lt;p&gt;是否有足够的见识，有足够的知识广度，了解别人的解决同样问题的做法是程序员能力的表现。&lt;/p&gt;&lt;p&gt;是否有快速的搜索出类似的解决方案，也是能力的表现。&lt;/p&gt;&lt;p&gt;1. PHP的Smarty 模版的设计哲学是什么？&lt;/p&gt;&lt;p&gt;2. Perl的Mason 模版的设计哲学是什么？&lt;/p&gt;&lt;p&gt;3. 什么是gettext?&lt;/p&gt;&lt;p&gt;4. 前端Javascript实现的模版中，目前最成熟的是哪个引擎？&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;【51CTO独家特稿】先摘录一段话勉励一下生日宝：&lt;/p&gt;&lt;p&gt;截止2010月6月，Facebook接近2000雇员。10个月时间从1100人增长到2000，一年时间员工人数翻了一番！&lt;/p&gt;&lt;p&gt;最大的两个团队是开发工程师和运维，都是400-500人的规模&lt;/p&gt;&lt;p&gt;猪头宝，在Facebook，运维跟开发是一样重要的。运维才不是用vender提供的软件，然后按manual去step by step的做事情。&lt;/p&gt;&lt;p&gt;有很多创造性的工作可以做。&lt;/p&gt;&lt;p&gt;猪宝你知道twitter是肿么更新服务器的么？&lt;/p&gt;&lt;p&gt;Twitter有几千台服务器，一旦网站要跟新，这几千台服务器上面的代码部署都要更新。&lt;/p&gt;&lt;p&gt;肿么让这几千台服务器快速的获得新代码呢？逐台服务器下载太慢了，数千台服务器同时向代码中央服务器获取新代码又会把中央服务器的带宽挤爆。&lt;/p&gt;&lt;p&gt;肿么办？&lt;/p&gt;&lt;p&gt;Twitter的运维工程师直接用了BT的协议，使用p2p下载来解决这个问题：&lt;a href="http://engineering.twitter.com/2010/07/murder-fast-datacenter-code-deploys.html"&gt;http://engineering.twitter.com/2010/07/murder-fast-datacenter-code-deploys.html&lt;/a&gt;&lt;/p&gt;&lt;p&gt;它们就这样把部署的时间从原来的40分钟大幅减少到只要12秒～～&lt;/p&gt;&lt;p&gt;运维，很多时候都是要编写脚本，把很多原本需要人手工做的事情通过脚本自动化管理起来。&lt;/p&gt;&lt;p&gt;这些脚本乃至系统的编写与开发，都是需要能力的。&lt;/p&gt;&lt;p&gt;运维的投入，都是为了节约别人的时间；而时间节约、效率提高、稳定性提高，这些都是有意义的。&lt;/p&gt;&lt;p&gt;之前猪宝去广州参加技术沙龙，有一个人人网之类的运维去讲自己的工作木有意义，是&amp;#8220;花卖白粉的心，赚卖白菜的钱&amp;#8221;；当场就被金山的过程改进经理周琦 Zoom.Quiet给吐槽了。&lt;/p&gt;&lt;p&gt;说他的态度不对，运维部门应该是一个盈利的部门，而不应该是一个被无视的部门；运维，应该是通过提高技术水平，提高效率，节约成本；以达到&amp;#8220;赚钱&amp;#8221;的目的。&lt;/p&gt;&lt;p&gt;caoz很推崇的一个技术牛人杨建；便是做运维的，在新浪、腾讯呆过，现在应该是被caoz收去4399了：&lt;a href="http://blog.sina.com.cn/iyangjian"&gt;http://blog.sina.com.cn/iyangjian&lt;/a&gt;&lt;/p&gt;&lt;p&gt;如果木有杨建这样的运维高手，新浪是木有可能支撑起一小时近20亿实际http请求处理量的：&lt;a href="http://blog.sina.com.cn/s/blog_466c66400100cfrj.html"&gt;http://blog.sina.com.cn/s/blog_466c66400100cfrj.html&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Facebook的有9个级别的代码发布流程：&lt;a href="http://www.dbanotes.net/arch/facebook_how_facebook_ships_code.html"&gt;http://www.dbanotes.net/arch/facebook_how_facebook_ships_code.html&lt;/a&gt; 这些都是运维的工程师牛B才有可能的；并且也确实解决了实际业务问题。&lt;/p&gt;&lt;p&gt;如果仅仅是做普通的SA，那么工作是很routine，很无聊，很没有技术含量的；但是如果能够提高，面临的问题是完全不一样的。&lt;/p&gt;&lt;p&gt;这跟烂ED与Hacker的区别也是一样。&lt;/p&gt;&lt;p&gt;实际上，很多职业都是一样；如果是做那底层的普通工作，都必然是无聊的，木有意义的。但一旦有进步，层次提高，面临的就是完全不一样的环境。&lt;/p&gt;&lt;p&gt;有做文书工作，收集、整理资料的律师；也有Alan Shore。&lt;/p&gt;&lt;p&gt;工作是否有意义，在于职位的层次。&lt;/p&gt;&lt;p&gt;亲亲猪头宝～&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;设计模式再&amp;#8220;高级&amp;#8221;一点，便是所谓的&amp;#8220;框架&amp;#8221;了。&lt;/p&gt;&lt;p&gt;从事Web开发，一般都会接触到MVC框架这个概念。&lt;/p&gt;&lt;p&gt;M：也就是Model，直接跟网站数据库相关。&lt;/p&gt;&lt;p&gt;V：也就是View，是网页的模版，跟显示数据相关。&lt;/p&gt;&lt;p&gt;C：则是Controller，相当于网站的业务逻辑。&lt;/p&gt;&lt;p&gt;MVC也不仅仅是应用于网站开发，它的概念实际上植根于桌面软件，并且在手机软件开发上也有应用。&lt;/p&gt;&lt;p&gt;MVC本身是一个设计模式，是一个被验证过的，可以用来很好归纳、管理代码的软件开发方式。&lt;/p&gt;&lt;p&gt;基于这样的设计模式，提供了很多相关的类库实现，则&amp;#8220;设计模式&amp;#8221;升级为&amp;#8220;框架&amp;#8221;。&lt;/p&gt;&lt;p&gt;MVC的任何一个方面，扩展出去讲，都可以讲上几天几夜。&lt;/p&gt;&lt;p&gt;今天只讲C。&lt;/p&gt;&lt;p&gt;传统上，php / asp / asp.net web form等，使用的是所谓的 Page Controller Patterns:http://martinfowler.com/eaaCatalog/pageController.html&lt;/p&gt;&lt;p&gt;Page Controller简单的说，便是一个网址对应一个程序文件。&lt;/p&gt;&lt;p&gt;所以，我们会看到大量类似： show.php / show.asp / show.aspx 的网址存在，这样的网址，背后都有相应同名的文件。&lt;/p&gt;&lt;p&gt;这样的模式，是网站从静态转向动态是最自然的改变方便，也最为容易让初学者接受。&lt;/p&gt;&lt;p&gt;但随着网站的复杂化，这样的模式会慢慢显得不够方便；比方说，多个不同的网址，映射到相同的处理；比方说，处理的时候，复用共同的资源。&lt;/p&gt;&lt;p&gt;页面内容的动态化，同一个程序文件，显示的内容是动态生成的 - 根据不同的query string，生成不同的内容，如：show.php?id=1234&lt;/p&gt;&lt;p&gt;网页程序内部，实际上是需要解析网址中的query string，并做不同的操作。&lt;/p&gt;&lt;p&gt;这实际上是一个映射的过程，将网址映射到相应的处理。&lt;/p&gt;&lt;p&gt;为了方便做这样的映射，慢慢的出现了所谓的 Front Controller Patterns:&amp;nbsp; &lt;a href="http://martinfowler.com/eaaCatalog/frontController.html"&gt;http://martinfowler.com/eaaCatalog/frontController.html&lt;/a&gt;&lt;/p&gt;&lt;p&gt;这是通过某种机制，将符合各种规则的网址请求映射到程序中的一个类，或者是一个函数处理。&lt;/p&gt;&lt;p&gt;一般上，是使用正则表达式解析网址，并映射。&lt;/p&gt;&lt;p&gt;将网址映射到一个类；&lt;br /&gt;urls = ("/home", "hello")&amp;nbsp; &lt;br /&gt;app = web.application(urls, globals())&amp;nbsp; &lt;br /&gt;class hello:&amp;nbsp;&amp;nbsp;&lt;br /&gt;def GET(self):&amp;nbsp;&amp;nbsp;&lt;br /&gt;return 'Hello, world!' &lt;/p&gt;&lt;p&gt;将网址请求映射到类，是相对较&amp;#8220;重&amp;#8221;的处理方式，比方说，需要处理类的初始化等等。&lt;/p&gt;&lt;p&gt;有的框架，也可以是一个函数，则相对&amp;#8220;轻量&amp;#8221;一些：&lt;br /&gt;(r'^$', 'home'),&amp;nbsp; &lt;br /&gt;&lt;br /&gt;def home(request):&amp;nbsp;&amp;nbsp;&lt;br /&gt;return HttpResponse("Hello, world.") &lt;/p&gt;&lt;p&gt;类、函数，均各有优劣，但实际差异很小：&lt;/p&gt;&lt;p&gt;映射到类的方式，往往还会根据不同的HTTP header映射到类里面中相映的函数，比方说，将对 /home 的HTTP GET请求映射给 hello 类的 GET 函数；而对 /home 的 HTTP POST请求映射给 hello 类的POST函数。&lt;/p&gt;&lt;p&gt;这部分 url routing的设计与实现，各种语言、平台上的功能均向正则表达式靠拢，大同小异。&lt;/p&gt;&lt;p&gt;有的可能专门为 restful 做了优化，但即便木有，自行实现也并不复杂。&lt;/p&gt;&lt;p&gt;很多请求，都会有一些常用的默认处理，比方说，检查用户是否登陆，检查用户是否有权限等等。&lt;/p&gt;&lt;p&gt;这些业务控制逻辑，是完全可以复用的。&lt;/p&gt;&lt;p&gt;在Page Controller的场景下，一般是通过继承来实现；而Front Controller场景下，而一般通过函数修饰符的风格实现，如：&lt;br /&gt;class UploadImgHandler(BaseHandler):&amp;nbsp; &lt;br /&gt;@tornado.web.authenticated&amp;nbsp; &lt;br /&gt;def post(self):&amp;nbsp;&amp;nbsp;&lt;br /&gt;XXX &lt;/p&gt;&lt;p&gt;(上述代码，实际上既使用了继承，也使用了修饰符。)&lt;/p&gt;&lt;p&gt;Controller的改进，目的在于更加方便的维护代码、修改业务逻辑。&lt;/p&gt;&lt;p&gt;如果程序员有良好的开发风格，基本是使用最基础的php page controller，也可以达到类似的效果。&lt;/p&gt;&lt;p&gt;各种&amp;#8220;先进框架&amp;#8221;，实际上是将常用的模式抽象出来，并通过便利的约定方式向程序员开放；如果程序员缺乏维护代码的意识，也很可能将良好的约定习惯用滥。&lt;/p&gt;&lt;p&gt;需要了解的，是为什么各框架的controller设计会有这样的设计，并用好；而不是死板的遵循&amp;#8220;开发指南&amp;#8221;。&lt;/p&gt;&lt;p&gt;在简单业务场景下，实际上page controller会更加方便。&lt;/p&gt;&lt;p&gt;有这么一个&amp;#8220;定理&amp;#8221;：概念越简单的模式，在处理简单场景时，是越便利；但随着场景复杂化，简单的模式会越来越难以维护。&lt;/p&gt;&lt;p&gt;而概念相对复杂、高级的模式，处理简单场景时，会相对麻烦；但随着场景复杂化，则比简单的模式容易维护。&lt;/p&gt;&lt;p&gt;&amp;#8220;复杂度是守恒&amp;#8221;的：&lt;br /&gt;模式简单，维护则复杂。&lt;br /&gt;模式复杂，维护则简单。&lt;/p&gt;&lt;p&gt;一个复杂的地方变简单了，则另一个地方会变复杂；保持代码结构的清晰，不要自己给自己添麻烦。&lt;/p&gt;&lt;p&gt;什么叫自己给自己添麻烦？&lt;/p&gt;&lt;p&gt;普通复数形式，加s: pigs / cats / dogs&lt;/p&gt;&lt;p&gt;已经可以很好了，但偏生有人要增加不规则复数：&lt;/p&gt;&lt;p&gt;sheep / mice / wives&lt;/p&gt;&lt;p&gt;这种就是自己给自己添麻烦。&lt;/p&gt;&lt;p&gt;作业：&lt;/p&gt;&lt;p&gt;1. 说说对 restful 的理解&lt;/p&gt;&lt;p&gt;2. 什么是 reverse proxy ?&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;【51CTO独家特稿】学以致用，很多时候，学习一样东西最好需要能够在实际中应用起来。&lt;/p&gt;&lt;p&gt;所以我在第2课"怎么看待牛人"中强调的必须&amp;#8220;看代码 + 写代码&amp;#8221;。&lt;/p&gt;&lt;p&gt;不过我在里面提到的例子&amp;#8220;ORM&amp;#8221;却并不好，ORM太过庞大。实际编码，应该是从小开始。&lt;/p&gt;&lt;p&gt;运维工作中更经常使用的是脚本语言，脚本程序甚至是shell命令都可以完成很多有意义的事情。&lt;/p&gt;&lt;p&gt;这些猪头应该在工作中体验很多；但作为程序员，程序能够发挥的作用也可以体现在生活上。&lt;/p&gt;&lt;p&gt;玩Draw Something单词想不出来，是完全可以写个程序来输出单词列表的。&lt;/p&gt;&lt;p&gt;上网下载一个英文单词词库；然后甚至可以用最傻X的方式去逐个单词检查，看Draw Something给出的字母是否能够组成各个单词。&lt;/p&gt;&lt;p&gt;程序首先是要完成需求，这里的需求仅仅是要方便玩游戏，猜出朋友的单词谜语。&lt;/p&gt;&lt;p&gt;程序运行慢点完全无所谓，千分之一秒输出结果，还是10秒输出结果，都不会影响这个需求的实现。&lt;/p&gt;&lt;p&gt;（当然，如果是玩Facebook上的限时拚单词游戏那需求又是不同。）&lt;/p&gt;&lt;p&gt;这种&amp;#8220;程序&amp;#8221;是所谓的Throw-away code，写完就扔。&lt;/p&gt;&lt;p&gt;像Draw Something这样的游戏，乐趣就在于努力去想、努力猜成功之后的成就感。有了这样一个程序，那就不用努力去想，游戏的乐趣也就会在瞬间丧失，&amp;#8220;破解工具&amp;#8221;自然也就得扔掉了。&lt;/p&gt;&lt;p&gt;即便写完就扔，但写这样的程序却有其意义。写与不写是差别是0与1的差别，这是本质的区别。&lt;/p&gt;&lt;p&gt;我会非常鄙视那些热衷于看各种语言的介绍但却一行程序都不写的人。&lt;/p&gt;&lt;p&gt;有的人，听说erlang很牛B，上网搜了一堆介绍，不断的感叹&amp;#8220;哇～Erlang确实很牛！&amp;#8221;，&amp;#8220;哦耶！Facebook Chat跟Web QQ都是在用erlang，果然erlang才是王道！&amp;#8221;&lt;/p&gt;&lt;p&gt;但是，他自己却不写任何一行erlang程序；有时，还会抱怨公司的管理层都是傻逼，这个项目用erlang再合适不过，为什么不用，为什么不给团队使用erlang的机会呢？&lt;/p&gt;&lt;p&gt;一定要写程序，没有机会，也要创造机会。&lt;/p&gt;&lt;p&gt;而在我看来，生活中这种&amp;#8220;玩游戏&amp;#8221;的机会再合适不过。&lt;/p&gt;&lt;p&gt;写了Draw Something的&amp;#8220;破解工具&amp;#8221;，会使得猜单词没有成就感，丧失游戏的乐趣；但，完成了一个程序去破解一个游戏，这本身也是一件有成就感的事情啊～&lt;/p&gt;&lt;p&gt;并且，游戏的乐趣会转移为编程的乐趣；而乐趣，是让自己变厉害的最大动力。&lt;/p&gt;&lt;p&gt;Geek享受这样的机会；而ED则等待别人享受这样的机会。&lt;/p&gt;&lt;p&gt;&amp;#8220;做，就对了&amp;#8221; - 慈济宗创始人 证严法师&lt;/p&gt;&lt;p&gt;作业：&lt;/p&gt;&lt;p&gt;1. 使用Perl 实现一个程序输入若干字母，输出这些字母所能组成的所有单词列表。素，就是要写个 Draw Something的&amp;#8220;破解工具&amp;#8221;。&lt;/p&gt;&lt;p&gt;2. 比较Perl的实现跟云风的lua实现有何不同：&lt;a href="https://github.com/cloudwu/guess-word"&gt;https://github.com/cloudwu/guess-word&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;【51CTO独家特稿】在前面的课程中提到PEAA中只有一页半的Active Record Pattern ( &lt;a href="http://martinfowler.com/eaaCatalog/activeRecord.html"&gt;http://martinfowler.com/eaaCatalog/activeRecord.html&lt;/a&gt; )影响了过去5年多6年的Web开发潮流。&lt;/p&gt;&lt;p&gt;这个潮流是由Ruby On Rails引领的。&lt;/p&gt;&lt;p&gt;RoR的作者DHH David Heinemeier Hansson是Hacker，他因为RoR在2005年被Google跟O'Reilly选为年度黑客。&lt;/p&gt;&lt;p&gt;他在设计RoR时，选用了Active Record作为RoR的M层。&lt;/p&gt;&lt;p&gt;Active Record非常简单，一个类对应一个表，一个对象实例对应一行数据；并且有简单的有Save / Delete以及查询等简单的函数操作。&lt;/p&gt;&lt;p&gt;严格的说，Active Record不是福勒所推崇的充血Domain Object模型 （ &lt;a href="http://martinfowler.com/bliki/AnemicDomainModel.html"&gt;http://martinfowler.com/bliki/AnemicDomainModel.html&lt;/a&gt; ），Active Record对象提供的功能函数太少，只有通用的数据操作方法，而不包涵业务逻辑；但它又不像POJO （ &lt;a href="http://martinfowler.com/bliki/POJO.html"&gt;http://martinfowler.com/bliki/POJO.html&lt;/a&gt; ） 那样完全的贫血。&lt;/p&gt;&lt;p&gt;（充血、贫血Domain Object之争，可以去iteye翻帖子）&lt;/p&gt;&lt;p&gt;从福勒 AnemicDomainModel 一文看，他在当年（2003）是推荐了充血Domain对象跟POJO，但过去几年在Web开发领域所流行的却是 Active Record这样两边都沾点，但却又不全是的中间妥协方案。&lt;/p&gt;&lt;p&gt;不搞教条主义，什么实用用什么，POJO不够，那么就加一点；充血太复杂，那么就减少一点。&lt;/p&gt;&lt;p&gt;从互联网的发展看，我一时间完全想不出有什么在理论上被设计得很好的模型，能够最终经历时间考验成为事实标准。&lt;/p&gt;&lt;p&gt;因特网的7层模型，实际用到的远不到7层；Java的EJB挂了；XML被JSON取代等等等等。&lt;/p&gt;&lt;p&gt;也许学院派提出的理论有他们的应用场景，只是，这样的场景，在快速发展互联网似乎很难找到例子。&lt;/p&gt;&lt;p&gt;互联网产品的业务相对简单，Active Record已经足够好，足够方便，因此大行其道。&lt;/p&gt;&lt;p&gt;另一方面，互联网产品做大后，也往往有着极大的性能要求，一个复杂的模型，是难以做性能优化的。&lt;/p&gt;&lt;p&gt;像Active Record，因为足够简单，Twitter在当年遇到性能问题的时候，便直接Hack掉RoR的实现，增加了 Cache-Money （ &lt;a href="https://github.com/nkallen/cache-money"&gt;https://github.com/nkallen/cache-money&lt;/a&gt; ） 这么一个透明的缓存层。&lt;/p&gt;&lt;p&gt;如果RoR使用的是充血对象模型，对象中有复杂的业务逻辑，如何增加透明的缓存呢？&lt;/p&gt;&lt;p&gt;Active Record的实际上是对数据库操作做了抽象。&lt;/p&gt;&lt;p&gt;封装、抽象是一门艺术。&lt;/p&gt;&lt;p&gt;什么该封装，什么该暴露，什么彻底不可见，需要拿捏得很准确。&lt;/p&gt;&lt;p&gt;最容易犯的错误是过度封装，使得一些本来很简单的底层操作，到了上层变得完全不能用；或者说，很难用。&lt;/p&gt;&lt;p&gt;开发者需要用到hack的方式，才能去做这些简单的操作。&lt;/p&gt;&lt;p&gt;Active Record便是一个抽象封装得恰到好处的例子。过度设计、过度封装的数据操作层？EJB。&lt;/p&gt;&lt;p&gt;按照教科书对OO的定义，OO的核心特性之一是：encapsulation &lt;a href="http://en.wikipedia.org/wiki/Encapsulation_%28object-oriented_programming%29"&gt;http://en.wikipedia.org/wiki/Encapsulation_%28object-oriented_programming%29&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Private属性、方法，对象外部是完全不能访问的。&lt;/p&gt;&lt;p&gt;但如果遇到了需要访问的场景怎么办？！&lt;/p&gt;&lt;p&gt;有的人会说：&amp;#8220;这样的场景本来就不应该出现，这是对象设计一开始没有做好造成的，错误的应该设成Public的属性设成了Private&amp;#8221;。&lt;/p&gt;&lt;p&gt;ORM，采用O =&amp;gt; R的映射的设计哲学，只考虑业务对象，完全不考虑底层数据库，数据库仅仅是一个可以被替换掉的持久层，它可以是关系型数据库、也可以是NoSQL，甚至是硬盘文件。&lt;/p&gt;&lt;p&gt;也就是说，Domain Object是把后端数据库给设成&amp;#8220;Private&amp;#8221;了，即便底层是关系型数据库，你也不可以直接去写SQL。&lt;/p&gt;&lt;p&gt;即便你使用的是MS SQL Server，你也不能去调用它特有的SQL特性。&lt;/p&gt;&lt;p&gt;Asp.Net刚出来的时候，微软曾经鼓吹过一个叫 N-Tiers 的架构：&lt;/p&gt;&lt;p&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/ms973279.aspx"&gt;http://msdn.microsoft.com/en-us/library/ms973279.aspx&lt;/a&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/bb384398.aspx"&gt;http://msdn.microsoft.com/en-us/library/bb384398.aspx&lt;/a&gt; 。&lt;/p&gt;&lt;p&gt;我曾经以为这是王道，直到我膝盖中了一箭&amp;#8230;&amp;#8230;呃，不，直到我看了Joel Spolsky写的 The Law of Leaky Abstractions：&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.joelonsoftware.com/articles/LeakyAbstractions.html"&gt;http://www.joelonsoftware.com/articles/LeakyAbstractions.html&lt;/a&gt;&lt;/p&gt;&lt;p&gt;理想很丰满，现实很骨感。&lt;/p&gt;&lt;p&gt;ORM工具再怎么封装都好，底层用了数据库，就是用了数据库。&lt;/p&gt;&lt;p&gt;开发者必然需要了解数据库的特性，能否直接调用数据库的特性，是一个选择。&lt;/p&gt;&lt;p&gt;是否要彻底对上层屏蔽掉数据库的存在，也是一个选择。&lt;/p&gt;&lt;p&gt;N-tiers架构推荐一层又一层的封装，如果错误使用，把选择当成教条，是会有噩梦的。&lt;/p&gt;&lt;p&gt;========&lt;/p&gt;&lt;p&gt;Python是一门很有趣的语言，它支持继承，能实现OO，但是缺乏 encapsulation 的语言支持。&lt;/p&gt;&lt;p&gt;Python根本就没有public / private这样的关键字，然后呢？&lt;/p&gt;&lt;p&gt;然后可以回过头再去看：&amp;#8220;这样的场景本来就不应该出现，这是对象设计一开始没有做好造成的，错误的应该设成Public的属性设成了Private&amp;#8221;。&lt;/p&gt;&lt;p&gt;这句话，这话说得对嘛？&lt;/p&gt;&lt;p&gt;作业：&lt;/p&gt;&lt;p&gt;1. N-tiers架构的噩梦场景是？&lt;/p&gt;&lt;p&gt;2. 什么系统/场景需要充分使用特定数据库的特性？&lt;/p&gt;&lt;img src="http://www.cnblogs.com/grenet/aggbug/2499069.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/grenet/archive/2012/05/14/2499069.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/grenet/archive/2012/05/04/2480682.html</id><title type="text">Win7下的内置FTP组件的设置详解</title><summary type="text">在局域网中共享文件，FTP是比较方便的方案之一。Win7内部集成了FTP，只是设置起来颇费一番功夫。着文以记之。 一、安装FTP组件 由于Win7默认没有安装FTP组件。故FTP的设置第一步就是安装FTP组件 点击：控制面板—》程序和功能—》打开或关闭Windows功能。勾选“FTP服务器”及“FTP服务”“FTP扩展性”，点击“确定”，安装FTP组件。如下图所示 二、添加FTP站点 点击：控制面板—》管理工具。选中“Internet信息服务(IIS)管理器”，如图 双击“Internet信息服务(IIS)管理器”。弹出管理器界面，如下图所示：...</summary><published>2012-05-04T02:41:00Z</published><updated>2012-05-04T02:41:00Z</updated><author><name>万仓一黍</name><uri>http://www.cnblogs.com/grenet/</uri></author><link rel="alternate" href="http://www.cnblogs.com/grenet/archive/2012/05/04/2480682.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/grenet/archive/2012/05/04/2480682.html"/><content type="html">&lt;p&gt;在局域网中共享文件，FTP是比较方便的方案之一。Win7内部集成了FTP，只是设置起来颇费一番功夫。着文以记之。&lt;/p&gt;&lt;p&gt;一、安装FTP组件&lt;/p&gt;&lt;p&gt;由于Win7默认没有安装FTP组件。故FTP的设置第一步就是安装FTP组件&lt;/p&gt;&lt;p&gt;点击：控制面板&amp;#8212;》程序和功能&amp;#8212;》打开或关闭Windows功能。勾选&amp;#8220;FTP服务器&amp;#8221;及&amp;#8220;FTP服务&amp;#8221;&amp;#8220;FTP扩展性&amp;#8221;，点击&amp;#8220;确定&amp;#8221;，安装FTP组件。如下图所示&lt;/p&gt;&lt;p&gt;&lt;img border="0" alt="" src="http://images.cnblogs.com/cnblogs_com/grenet/Windows.png" width="429" height="425" /&gt;&lt;/p&gt;&lt;p&gt;二、添加FTP站点&lt;/p&gt;&lt;p&gt;点击：控制面板&amp;#8212;》管理工具。选中&amp;#8220;Internet信息服务(IIS)管理器&amp;#8221;，如图&lt;/p&gt;&lt;p&gt;&lt;img border="0" alt="" src="http://images.cnblogs.com/cnblogs_com/grenet/manage.png" width="651" height="464" /&gt;&lt;/p&gt;&lt;p&gt;双击&amp;#8220;Internet信息服务(IIS)管理器&amp;#8221;。弹出管理器界面，如下图所示：&lt;/p&gt;&lt;p&gt;&lt;img border="0" alt="" src="http://images.cnblogs.com/cnblogs_com/grenet/IIS.png" /&gt;&lt;/p&gt;&lt;p&gt;单击选中&amp;#8220;网站&amp;#8221;，并且在其上右击，选择&amp;#8220;添加FTP站点&amp;#8221;，出现&amp;#8220;站点信息&amp;#8221;界面，如下所示：&lt;/p&gt;&lt;p&gt;&lt;img border="0" alt="" src="http://images.cnblogs.com/cnblogs_com/grenet/FTP1.png" width="687" height="585" /&gt;&lt;/p&gt;&lt;p&gt;给FTP取名（本例是：zhu），以及设置FTP站点的物理路径（本例是：c:\ftp），点击&amp;#8220;下一步&amp;#8221;，出现&amp;#8220;绑定和SSL设置&amp;#8221;界面，如下图所示&lt;/p&gt;&lt;p&gt;&lt;img border="0" alt="" src="http://images.cnblogs.com/cnblogs_com/grenet/FTP2.png" width="687" height="585" /&gt;&lt;/p&gt;&lt;p&gt;IP设置为本机的IP地址，端口用FTP默认的21，SSL勾选&amp;#8220;无&amp;#8221;。点击&amp;#8220;下一步&amp;#8221;，出现&amp;#8220;身份验证和授权信息&amp;#8221;界面，如下图所示：&lt;/p&gt;&lt;p&gt;&lt;img border="0" alt="" src="http://images.cnblogs.com/cnblogs_com/grenet/FTP3.png" width="687" height="585" /&gt;&lt;/p&gt;&lt;p&gt;如果只是想设置简单的FTP，则&amp;#8220;身份验证&amp;#8221;和&amp;#8220;授权&amp;#8221;都勾选&amp;#8220;匿名&amp;#8221;，并且给匿名设置相应的权限。本例中，还要给FTP配置帐号，以及帐号的权限，故&amp;#8220;身份验证&amp;#8221;勾选&amp;#8220;基本&amp;#8221;，&amp;#8220;授权&amp;#8221;勾选&amp;#8220;未选定&amp;#8221;，点击&amp;#8220;完成&amp;#8221;，完成FTP站点的设置。&lt;/p&gt;&lt;p&gt;三、设置FTP帐号以及权限&lt;/p&gt;&lt;p&gt;由于Win7下的FTP帐号是Windows用户帐号。所以，先得添加两个用户帐号，一个是View，可以浏览、下载FTP内容；一个是Admin，完全控制FTP。&lt;/p&gt;&lt;p&gt;点击：控制面板&amp;#8212;》管理工具&amp;#8212;》计算机管理。在计算机管理的界面的左侧，点击：系统工具&amp;#8212;》本地用户和组&amp;#8212;》用户，右侧显示所有用户。如下图所示：&lt;/p&gt;&lt;p&gt;&lt;img border="0" alt="" src="http://images.cnblogs.com/cnblogs_com/grenet/user.png" width="623" height="442" /&gt;&lt;/p&gt;&lt;p&gt;在&amp;#8220;用户&amp;#8221;上右击，出现&amp;#8220;新用户&amp;#8221;，如下所示：&lt;/p&gt;&lt;p&gt;&lt;img border="0" alt="" src="http://images.cnblogs.com/cnblogs_com/grenet/newuser.png" width="394" height="365" /&gt;&lt;/p&gt;&lt;p&gt;在用户名中输入View，设置好密码，去掉勾选&amp;#8220;用户下次登陆时须更改密码&amp;#8221;，勾选&amp;#8220;用户不能更改密码&amp;#8221;和&amp;#8220;密码永不过期&amp;#8221;。点击&amp;#8220;创建&amp;#8221;，完成用户View的创建。同样的步骤，创建Admin用户。由于Windows默认将用户添加到Users组，你可以将刚才的两个用户从Users组中删除。方法是在&amp;#8220;计算机管理&amp;#8221;中点击&amp;#8220;组&amp;#8221;，在右侧的列表中找到Users，双击之，出现如下界面，点中用户View，点&amp;#8220;删除&amp;#8221;，点中用户Admin，点&amp;#8220;删除&amp;#8221;。将两个用户从Users组中删除。&lt;/p&gt;&lt;p&gt;&lt;img border="0" alt="" src="http://images.cnblogs.com/cnblogs_com/grenet/userremove.png" width="414" height="430" /&gt;&lt;/p&gt;&lt;p&gt;接下来，在FTP站点中，给View和Admin添加权限。&lt;/p&gt;&lt;p&gt;点击：控制面板&amp;#8212;》管理工具&amp;#8212;》Internet信息服务(IIS)管理器。点中刚才新建的FTP站点。点中&amp;#8220;FTP授权规则&amp;#8221;。如下图所示：&lt;/p&gt;&lt;p&gt;&lt;img border="0" alt="" src="http://images.cnblogs.com/cnblogs_com/grenet/FTPRIGHT.png" width="734" height="499" /&gt;&lt;/p&gt;&lt;p&gt;点击右侧的&amp;#8220;编辑权限&amp;#8221;，对FTP站点文件夹添加用户权限。在弹出的窗口中，点击&amp;#8220;安全&amp;#8221;标签。，如下图所示：&lt;/p&gt;&lt;p&gt;&lt;img border="0" alt="" src="http://images.cnblogs.com/cnblogs_com/grenet/FolderRight-1.png" width="377" height="426" /&gt;&lt;/p&gt;&lt;p&gt;点&amp;#8220;编辑&amp;#8221;，出现权限的窗口，如下：&lt;/p&gt;&lt;p&gt;&lt;img border="0" alt="" src="http://images.cnblogs.com/cnblogs_com/grenet/FolderRight-1.png" width="377" height="426" /&gt;&lt;/p&gt;&lt;p&gt;点&amp;#8220;添加&amp;#8221;，在&amp;#8220;输入对象名称来选择&amp;#8221;中输入View，点&amp;#8220;确定&amp;#8221;，添加View用户。如下所示：&lt;/p&gt;&lt;p&gt;&lt;img border="0" alt="" src="http://images.cnblogs.com/cnblogs_com/grenet/FolderRight-2.png" width="471" height="257" /&gt;&lt;/p&gt;&lt;p&gt;添加的View用户，默认是只有读取、列出的权限。在依法添加Admin用户，给Admin用户添加完全控制的权限。如下所示：&lt;/p&gt;&lt;p&gt;&lt;img border="0" alt="" src="http://images.cnblogs.com/cnblogs_com/grenet/FolderRight-3.png" width="377" height="426" /&gt;&lt;/p&gt;&lt;p&gt;再回到&amp;#8220;Internet信息服务(IIS)管理器&amp;#8221;窗口，双击刚才选中的&amp;#8220;FTP授权规则&amp;#8221;，在FTP站点中对View和Admin授权。如下所示：&lt;/p&gt;&lt;p&gt;&lt;img border="0" alt="" src="http://images.cnblogs.com/cnblogs_com/grenet/FTPRIGHT-2.png" width="734" height="499" /&gt;&lt;/p&gt;&lt;p&gt;点击右侧的&amp;#8220;添加允许规则&amp;#8221;，在弹出的窗口中，勾选&amp;#8220;指定的用户&amp;#8221;，输入View，在下方的&amp;#8220;权限&amp;#8221;中，勾选&amp;#8220;读取&amp;#8221;。如下所示：&lt;/p&gt;&lt;p&gt;&lt;img border="0" alt="" src="http://images.cnblogs.com/cnblogs_com/grenet/FTPRIGHT-3.png" width="483" height="483" /&gt;&lt;/p&gt;&lt;p&gt;点&amp;#8220;确定&amp;#8221;，给FTP站点添加View用户，相应的权限是读取。再给FTP站点添加Admin用户，相应的权限是读取和写入。&lt;/p&gt;&lt;p&gt;至此，FTP的站点设置就完成了。站点文件夹是c:\ftp，View用户有读取（浏览和下载）的权限，Admin用户有读取和写入（上传和删除）的权限。当然，还可以根据实际的情况添加用户及相应的权限，也可以将用户添加进组，再给组设置权限。还可以添加匿名用户等等，不一而足了。&lt;/p&gt;&lt;p&gt;然而，事情远远没有结束。如果，你急于做测试的话。会发现，在本机上测试正常，但是用别的机器测试FTP的话，会发现连接不上。问题出在Win7下的防火墙。如果你把防火墙关掉，你会发现FTP恢复了正常，但你也不能因为要用FTP，就把Win7的防火墙关掉。要想在Win7开着防火墙的时候还要正常使用，还必须得在防火墙中进行一番设置&lt;/p&gt;&lt;p&gt;四、Win7的防火墙设置&lt;/p&gt;&lt;p&gt;点击：控制面板&amp;#8212;》Windows防火墙。点击左侧的&amp;#8220;允许程序或功能通过Windows防火墙&amp;#8221;，选中&amp;#8220;FTP服务器&amp;#8221;，将后面的两个框都勾选，如下所示：&lt;/p&gt;&lt;p&gt;&lt;img border="0" alt="" src="http://images.cnblogs.com/cnblogs_com/grenet/firewall.png" width="792" height="585" /&gt;&lt;/p&gt;&lt;p&gt;这是网上绝大多数介绍的防火墙设置。然而还不够，你做测试的话会发现，还是连接不上。还必须在防火墙中进一步做设置。&lt;/p&gt;&lt;p&gt;点击下方的&amp;#8220;允许运行另一程序&amp;#8221;，在弹出窗口里，点&amp;#8220;浏览&amp;#8221;，找到C:\Windows\System32\inetsrv\inetinfo.exe，点添加，也就是上图中的Internet Infomation Services。将后面的两个框也都选中。因为在Win7下，FTP是IIS的一个组件，因此也必须在防火墙中将IIS设置为允许。而IIS又不在默认的列表中，因此得手动添加。&lt;/p&gt;&lt;p&gt;遗憾的是，这样设置，FTP还是不能正常使用。由于FTP用的是21端口，因此在防火墙中还得添加出站和入站的端口规则。&lt;/p&gt;&lt;p&gt;在Windows防火墙窗口里，点击左侧的&amp;#8220;高级设置&amp;#8221;，弹出高级安全防火墙窗口，点击左侧的&amp;#8220;入站规则&amp;#8221;，如下图所示：&lt;/p&gt;&lt;p&gt;&lt;img border="0" alt="" src="http://images.cnblogs.com/cnblogs_com/grenet/firewall-2.png" width="1061" height="791" /&gt;&lt;/p&gt;&lt;p&gt;点击右侧的&amp;#8220;新建规则&amp;#8221;，出现向导界面，勾选&amp;#8220;端口&amp;#8221;，如图：&lt;/p&gt;&lt;p&gt;&lt;img border="0" alt="" src="http://images.cnblogs.com/cnblogs_com/grenet/firewall-3.png" width="728" height="545" /&gt;&lt;/p&gt;&lt;p&gt;点击&amp;#8220;下一步&amp;#8221;，勾选TCP（FTP用的是TCP协议），再勾选特定本地端口，输入21（FTP用的是21端口）如图所示：&lt;/p&gt;&lt;p&gt;&lt;img border="0" alt="" src="http://images.cnblogs.com/cnblogs_com/grenet/firewall-4.png" width="728" height="545" /&gt;&lt;/p&gt;&lt;p&gt;点击&amp;#8220;下一步&amp;#8221;，勾选&amp;#8220;允许连接&amp;#8221;，如图：&lt;/p&gt;&lt;p&gt;&lt;img border="0" alt="" src="http://images.cnblogs.com/cnblogs_com/grenet/firewall-5.png" width="728" height="545" /&gt;&lt;/p&gt;&lt;p&gt;点击&amp;#8220;下一步&amp;#8221;，默认的都选上，如图：&lt;/p&gt;&lt;p&gt;&lt;img border="0" alt="" src="http://images.cnblogs.com/cnblogs_com/grenet/firewall-6.png" width="728" height="545" /&gt;&lt;/p&gt;&lt;p&gt;点击&amp;#8220;下一步&amp;#8221;，在名称里输入名字，本例中是21，如图&lt;/p&gt;&lt;p&gt;&lt;img border="0" alt="" src="http://images.cnblogs.com/cnblogs_com/grenet/firewall-7.png" width="728" height="545" /&gt;&lt;/p&gt;&lt;p&gt;点击&amp;#8220;完成&amp;#8221;，完成入站规则的设置，在用同样的方法，完成出站规则的设置，同样是21端口。&lt;/p&gt;&lt;p&gt;至此，在Win7的防火墙就已经设置好了。现在测试基本上就正常了。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;不过，还有个小问题：&lt;/p&gt;&lt;p&gt;在用IE浏览FTP的时候，虽然可以登录，但是没法显示FTP内容。这个是IE的设置问题。在Internet选项中，将&amp;#8220;使用被动FTP（用于防火墙和DSL调制解调器的兼容性）&amp;#8221;勾掉就解决了不能浏览的问题。如下图所示：&lt;/p&gt;&lt;p&gt;&lt;img border="0" alt="" src="http://images.cnblogs.com/cnblogs_com/grenet/ie.png" width="428" height="505" /&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;后序。总体来说，Win7的内置FTP设置比一些第三方的FTP软件设置要繁琐一些。但是在某些场合下，还只能用Win7的内置FTP。以上的内容都是网上搜集来的，加上本人的亲测。如果谁在FTP设置上还有什么问题，欢迎交流。&lt;/p&gt;&lt;img src="http://www.cnblogs.com/grenet/aggbug/2480682.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/grenet/archive/2012/05/04/2480682.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/grenet/archive/2012/04/24/2467571.html</id><title type="text">小议IE8下的KB927917错误</title><summary type="text">日前，在进行JS测试的时候，不巧碰到了IE8下的KB927917的错误。在网络上搜寻了一番之后，结合实际，给出了自己的解决方案。下面用示例来说明。 先看看下面的示例一的网页代码：&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt;&lt;html xmlns="http://www.w3.org/1999/xhtml"&gt;&lt;h</summary><published>2012-04-24T02:02:00Z</published><updated>2012-04-24T02:02:00Z</updated><author><name>万仓一黍</name><uri>http://www.cnblogs.com/grenet/</uri></author><link rel="alternate" href="http://www.cnblogs.com/grenet/archive/2012/04/24/2467571.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/grenet/archive/2012/04/24/2467571.html"/><content type="html">&lt;p&gt;日前，在进行JS测试的时候，不巧碰到了IE8下的KB927917的错误。在网络上搜寻了一番之后，结合实际，给出了自己的解决方案。下面用示例来说明。&lt;/p&gt;&lt;p&gt;先看看下面的示例一的网页代码：&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;style&gt;.cf1 {color:#0000FF}.cf2 {color:#FFFFFF}.cf3 {color:#A31515}.cf4 {color:#000000}.cf5 {color:#FF0000}&lt;/style&gt;&lt;div style="font-family: Verdana; color: black; font-size: 12pt"&gt;&lt;span class="cf1"&gt;&amp;lt;!&lt;/span&gt;&lt;span class="cf3"&gt;DOCTYPE&lt;/span&gt; &lt;span class="cf5"&gt;html&lt;/span&gt; &lt;span class="cf5"&gt;PUBLIC&lt;/span&gt; &lt;span class="cf1"&gt;"-//W3C//DTD XHTML 1.0 Transitional//EN"&lt;/span&gt; &lt;span class="cf1"&gt;"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf1"&gt;&amp;lt;&lt;/span&gt;&lt;span class="cf3"&gt;html&lt;/span&gt; &lt;span class="cf5"&gt;xmlns&lt;/span&gt;&lt;span class="cf1"&gt;="http://www.w3.org/1999/xhtml"&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf1"&gt;&amp;lt;&lt;/span&gt;&lt;span class="cf3"&gt;head&lt;/span&gt;&lt;span class="cf1"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf1"&gt;&lt;/span&gt;&lt;span class="cf1"&gt;&amp;lt;&lt;/span&gt;&lt;span class="cf3"&gt;title&lt;/span&gt;&lt;span class="cf1"&gt;&amp;gt;&lt;/span&gt;KB927917&lt;span class="cf1"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="cf3"&gt;title&lt;/span&gt;&lt;span class="cf1"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf1"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf1"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="cf3"&gt;head&lt;/span&gt;&lt;span class="cf1"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf1"&gt;&amp;lt;&lt;/span&gt;&lt;span class="cf3"&gt;body&lt;/span&gt;&lt;span class="cf1"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf1"&gt;&lt;/span&gt;&lt;span class="cf1"&gt;&amp;lt;&lt;/span&gt;&lt;span class="cf3"&gt;div&lt;/span&gt; &lt;span class="cf5"&gt;id&lt;/span&gt;&lt;span class="cf1"&gt;="GrandFather"&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf1"&gt;&lt;/span&gt;&lt;span class="cf1"&gt;&amp;lt;&lt;/span&gt;&lt;span class="cf3"&gt;div&lt;/span&gt; &lt;span class="cf5"&gt;id&lt;/span&gt;&lt;span class="cf1"&gt;="Uncle"&amp;gt;&lt;/span&gt;This is Uncle&lt;span class="cf1"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="cf3"&gt;div&lt;/span&gt;&lt;span class="cf1"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf1"&gt;&lt;/span&gt;&lt;span class="cf1"&gt;&amp;lt;&lt;/span&gt;&lt;span class="cf3"&gt;div&lt;/span&gt; &lt;span class="cf5"&gt;id&lt;/span&gt;&lt;span class="cf1"&gt;="Father"&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf1"&gt;&lt;/span&gt;&lt;span class="cf1"&gt;&amp;lt;&lt;/span&gt;&lt;span class="cf3"&gt;script&lt;/span&gt;　 &lt;span class="cf5"&gt;type&lt;/span&gt;&lt;span class="cf1"&gt;="text/javascript"&lt;/span&gt;　&lt;span class="cf1"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf1"&gt;&lt;/span&gt;&lt;span class="cf1"&gt;function&lt;/span&gt; $(Id){&lt;span class="cf1"&gt;return&lt;/span&gt; document.getElementById(Id);}&lt;br /&gt;document.write(&lt;span class="cf3"&gt;'&amp;lt;div id="Nephew"&amp;gt;This is Nephew&amp;lt;/div&amp;gt;'&lt;/span&gt;);&lt;br /&gt;$(&lt;span class="cf3"&gt;'GrandFather'&lt;/span&gt;).appendChild($(&lt;span class="cf3"&gt;'Nephew'&lt;/span&gt;));&lt;br /&gt;&lt;span class="cf1"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="cf3"&gt;script&lt;/span&gt;&lt;span class="cf1"&gt;&amp;gt;&lt;/span&gt;　 &lt;br /&gt;&lt;span class="cf1"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="cf3"&gt;div&lt;/span&gt;&lt;span class="cf1"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf1"&gt;&lt;/span&gt;&lt;span class="cf1"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="cf3"&gt;div&lt;/span&gt;&lt;span class="cf1"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf1"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="cf3"&gt;body&lt;/span&gt;&lt;span class="cf1"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf1"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="cf3"&gt;html&lt;/span&gt;&lt;span class="cf1"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf1"&gt;&lt;/span&gt;&lt;/div&gt;&lt;p&gt;这段示例代码很简单，在id为Father的div中，用JS生成一个id为Nephew的div，并将该div添加为id为GrandFather的div的子元素。&lt;/p&gt;&lt;p&gt;然而，这段代码在IE8下浏览，浏览器报了KB927917的错误。该错误所示如下：&lt;/p&gt;&lt;p&gt;HTML Parsing Error: Unable to modify the parent container element before the child element is closed (KB927917)&lt;/p&gt;&lt;p&gt;我对该段英文的理解是：&lt;strong&gt;在子元素闭合之前不能对其父容器元素进行修改&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;上面的示例代码，JS的代码是放在id为Father的div中，在执行JS代码时，该div还没有闭合。此时JS试图添加子元素到其父容器（id为GrandFather的div）时，就引发了KB927917的错误。&lt;/p&gt;&lt;p&gt;虽然上面的代码在IE8下会报KB927917的错误，但是渲染还是正常的。然而，笔者在测试其他网页的时候，由于该错误，导致页面的按钮失效。因此，还是要想办法解决该问题。&lt;/p&gt;&lt;p&gt;网上提到该错误的时候，几乎都是提到一种解决方案，将JS代码移到Body标签的后面。经过笔者的实验，发现将JS代码移到id为GrandFather的div外面就可以了。也就是JS代码的执行不影响div的闭合就可以了。&lt;/p&gt;&lt;p&gt;下面是示例二的网页代码&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div style="font-family: Verdana; color: black; font-size: 12pt"&gt;&lt;span class="cf1"&gt;&amp;lt;!&lt;/span&gt;&lt;span class="cf3"&gt;DOCTYPE&lt;/span&gt; &lt;span class="cf5"&gt;html&lt;/span&gt; &lt;span class="cf5"&gt;PUBLIC&lt;/span&gt; &lt;span class="cf1"&gt;"-//W3C//DTD XHTML 1.0 Transitional//EN"&lt;/span&gt; &lt;span class="cf1"&gt;"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf1"&gt;&amp;lt;&lt;/span&gt;&lt;span class="cf3"&gt;html&lt;/span&gt; &lt;span class="cf5"&gt;xmlns&lt;/span&gt;&lt;span class="cf1"&gt;="http://www.w3.org/1999/xhtml"&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf1"&gt;&amp;lt;&lt;/span&gt;&lt;span class="cf3"&gt;head&lt;/span&gt;&lt;span class="cf1"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf1"&gt;&lt;/span&gt;&lt;span class="cf1"&gt;&amp;lt;&lt;/span&gt;&lt;span class="cf3"&gt;title&lt;/span&gt;&lt;span class="cf1"&gt;&amp;gt;&lt;/span&gt;KB927917&lt;span class="cf1"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="cf3"&gt;title&lt;/span&gt;&lt;span class="cf1"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf1"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf1"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="cf3"&gt;head&lt;/span&gt;&lt;span class="cf1"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf1"&gt;&amp;lt;&lt;/span&gt;&lt;span class="cf3"&gt;body&lt;/span&gt;&lt;span class="cf1"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf1"&gt;&lt;/span&gt;&lt;span class="cf1"&gt;&amp;lt;&lt;/span&gt;&lt;span class="cf3"&gt;div&lt;/span&gt; &lt;span class="cf5"&gt;id&lt;/span&gt;&lt;span class="cf1"&gt;="GrandFather"&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf1"&gt;&lt;/span&gt;&lt;span class="cf1"&gt;&amp;lt;&lt;/span&gt;&lt;span class="cf3"&gt;div&lt;/span&gt; &lt;span class="cf5"&gt;id&lt;/span&gt;&lt;span class="cf1"&gt;="Uncle"&amp;gt;&lt;/span&gt;This is Uncle&lt;span class="cf1"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="cf3"&gt;div&lt;/span&gt;&lt;span class="cf1"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf1"&gt;&lt;/span&gt;&lt;span class="cf1"&gt;&amp;lt;&lt;/span&gt;&lt;span class="cf3"&gt;div&lt;/span&gt; &lt;span class="cf5"&gt;id&lt;/span&gt;&lt;span class="cf1"&gt;="Father"&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf1"&gt;&lt;/span&gt;　 &lt;span class="cf1"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="cf3"&gt;div&lt;/span&gt;&lt;span class="cf1"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf1"&gt;&lt;/span&gt;&lt;span class="cf1"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="cf3"&gt;div&lt;/span&gt;&lt;span class="cf1"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf1"&gt;&lt;/span&gt;&lt;span class="cf1"&gt;&amp;lt;&lt;/span&gt;&lt;span class="cf3"&gt;script&lt;/span&gt;　 &lt;span class="cf5"&gt;type&lt;/span&gt;&lt;span class="cf1"&gt;="text/javascript"&lt;/span&gt;　&lt;span class="cf1"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf1"&gt;&lt;/span&gt;&lt;span class="cf1"&gt;function&lt;/span&gt; $(Id){&lt;span class="cf1"&gt;return&lt;/span&gt; document.getElementById(Id);}&lt;br /&gt;document.write(&lt;span class="cf3"&gt;'&amp;lt;div id="Nephew"&amp;gt;This is Nephew&amp;lt;/div&amp;gt;'&lt;/span&gt;);&lt;br /&gt;$(&lt;span class="cf3"&gt;'GrandFather'&lt;/span&gt;).appendChild($(&lt;span class="cf3"&gt;'Nephew'&lt;/span&gt;));&lt;br /&gt;&lt;span class="cf1"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="cf3"&gt;script&lt;/span&gt;&lt;span class="cf1"&gt;&amp;gt;&lt;/span&gt;　 &lt;br /&gt;&lt;br /&gt;&lt;span class="cf1"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="cf3"&gt;body&lt;/span&gt;&lt;span class="cf1"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf1"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="cf3"&gt;html&lt;/span&gt;&lt;span class="cf1"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf1"&gt;&lt;/span&gt;&lt;/div&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;上面的示例代码就解决了IE8下的KB927917的错误。而没必要将JS代码放置在Body的标签后面。&lt;/p&gt;&lt;p&gt;再回看示例一的代码。在JS代码执行的时候，id为Father的div没有闭合，而其父容器id为GrandFather的div此时也没有闭合。我突然想到，是不是id为GrandFather的div没有闭合才是引发KB927917错误的主要原因。为此，做了一个实验，修改了一下代码，将原本&amp;#8220;添加为id为GrandFather的div的子元素&amp;#8221;改成&amp;#8220;添加为id为Uncle的div的子元素&amp;#8221;。因为在执行这段JS的代码时，id为GrandFather的div没有闭合，而id为Uncle的div已经闭合。&lt;/p&gt;&lt;p&gt;下面是示例三的网页代码：&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div style="font-family: Verdana; color: black; font-size: 12pt"&gt;&lt;span class="cf1"&gt;&amp;lt;!&lt;/span&gt;&lt;span class="cf3"&gt;DOCTYPE&lt;/span&gt; &lt;span class="cf5"&gt;html&lt;/span&gt; &lt;span class="cf5"&gt;PUBLIC&lt;/span&gt; &lt;span class="cf1"&gt;"-//W3C//DTD XHTML 1.0 Transitional//EN"&lt;/span&gt; &lt;span class="cf1"&gt;"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf1"&gt;&amp;lt;&lt;/span&gt;&lt;span class="cf3"&gt;html&lt;/span&gt; &lt;span class="cf5"&gt;xmlns&lt;/span&gt;&lt;span class="cf1"&gt;="http://www.w3.org/1999/xhtml"&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf1"&gt;&amp;lt;&lt;/span&gt;&lt;span class="cf3"&gt;head&lt;/span&gt;&lt;span class="cf1"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf1"&gt;&lt;/span&gt;&lt;span class="cf1"&gt;&amp;lt;&lt;/span&gt;&lt;span class="cf3"&gt;title&lt;/span&gt;&lt;span class="cf1"&gt;&amp;gt;&lt;/span&gt;KB927917&lt;span class="cf1"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="cf3"&gt;title&lt;/span&gt;&lt;span class="cf1"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf1"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf1"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="cf3"&gt;head&lt;/span&gt;&lt;span class="cf1"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf1"&gt;&amp;lt;&lt;/span&gt;&lt;span class="cf3"&gt;body&lt;/span&gt;&lt;span class="cf1"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf1"&gt;&lt;/span&gt;&lt;span class="cf1"&gt;&amp;lt;&lt;/span&gt;&lt;span class="cf3"&gt;div&lt;/span&gt; &lt;span class="cf5"&gt;id&lt;/span&gt;&lt;span class="cf1"&gt;="GrandFather"&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf1"&gt;&lt;/span&gt;&lt;span class="cf1"&gt;&amp;lt;&lt;/span&gt;&lt;span class="cf3"&gt;div&lt;/span&gt; &lt;span class="cf5"&gt;id&lt;/span&gt;&lt;span class="cf1"&gt;="Uncle"&amp;gt;&lt;/span&gt;This is Uncle&lt;span class="cf1"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="cf3"&gt;div&lt;/span&gt;&lt;span class="cf1"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf1"&gt;&lt;/span&gt;&lt;span class="cf1"&gt;&amp;lt;&lt;/span&gt;&lt;span class="cf3"&gt;div&lt;/span&gt; &lt;span class="cf5"&gt;id&lt;/span&gt;&lt;span class="cf1"&gt;="Father"&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf1"&gt;&lt;/span&gt;&lt;span class="cf1"&gt;&amp;lt;&lt;/span&gt;&lt;span class="cf3"&gt;script&lt;/span&gt;　 &lt;span class="cf5"&gt;type&lt;/span&gt;&lt;span class="cf1"&gt;="text/javascript"&lt;/span&gt;　&lt;span class="cf1"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf1"&gt;&lt;/span&gt;&lt;span class="cf1"&gt;function&lt;/span&gt; $(Id){&lt;span class="cf1"&gt;return&lt;/span&gt; document.getElementById(Id);}&lt;br /&gt;document.write(&lt;span class="cf3"&gt;'&amp;lt;div id="Nephew"&amp;gt;This is Nephew&amp;lt;/div&amp;gt;'&lt;/span&gt;);&lt;br /&gt;$(&lt;span class="cf3"&gt;'Uncle'&lt;/span&gt;).appendChild($(&lt;span class="cf3"&gt;'Nephew'&lt;/span&gt;));&lt;br /&gt;&lt;span class="cf1"&gt;　&amp;lt;/&lt;/span&gt;&lt;span class="cf3"&gt;script&lt;/span&gt;&lt;span class="cf1"&gt;&amp;gt;&lt;/span&gt;　 &lt;br /&gt;&lt;span class="cf1"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="cf3"&gt;div&lt;/span&gt;&lt;span class="cf1"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf1"&gt;&lt;/span&gt;&lt;span class="cf1"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="cf3"&gt;div&lt;/span&gt;&lt;span class="cf1"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf1"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="cf3"&gt;body&lt;/span&gt;&lt;span class="cf1"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf1"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="cf3"&gt;html&lt;/span&gt;&lt;span class="cf1"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf1"&gt;&lt;/span&gt;&lt;/div&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;测试这段代码，一切正常。这也印证我之前的判断&amp;#8212;&amp;#8212;&lt;strong&gt;id为GrandFather的div没有闭合才是引发KB927917错误的主要原因&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;经过上面的测试，可以总结为，当JS试图修改一个没有闭合的元素的时候，会引发KB927917的错误。&lt;/p&gt;&lt;p&gt;最后说两句题外话，同样的示例一的网页在IE9下浏览正常，似乎IE9自动修正该错误。网上说，该错误在IE7和IE6会引发长时间的读取动作，就像死机了一样，我没有测试，不好评说。另，在VS2008中直接启动用IE8浏览，该错误也似乎被修正，这是什么原因，也就没有深究了。&lt;/p&gt;&lt;img src="http://www.cnblogs.com/grenet/aggbug/2467571.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/grenet/archive/2012/04/24/2467571.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/grenet/archive/2012/04/07/2436384.html</id><title type="text">一道面试附加题的另类求解</title><summary type="text">有一段时间没有写博客了。今日闲逛的时候，看到一篇博客“4月7日某公司在华南地区举办了一年一度的"开发者"聚会——记某公司笔试”。里面有作者回忆的面试题。其中一题引起了笔者的注意，题目如下： 题目：已知一个数组a[N]，构造一个数组b[N]，构造规则：b[i]=a[0]*a[1]*a[2]...a[N]/a[i]; 要求： 1、不可以使用除法； 2、时间复杂度为O(n)，空间复杂度为S(0)； 3、除遍历使用的变量外，不可以使用其它变量； 看似简单，想想也废了一番脑筋。 最先想到的是就是原作者想到的方法，代码如下（用的是VB2008）： Public Sha...</summary><published>2012-04-07T11:23:00Z</published><updated>2012-04-07T11:23:00Z</updated><author><name>万仓一黍</name><uri>http://www.cnblogs.com/grenet/</uri></author><link rel="alternate" href="http://www.cnblogs.com/grenet/archive/2012/04/07/2436384.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/grenet/archive/2012/04/07/2436384.html"/><content type="html">&lt;p&gt;有一段时间没有写博客了。今日闲逛的时候，看到一篇博客&amp;#8220;&lt;a href="http://www.cnblogs.com/rond/archive/2012/04/07/2436050.html"&gt;4月7日某公司在华南地区举办了一年一度的"开发者"聚会&amp;#8212;&amp;#8212;记某公司笔试&lt;/a&gt;&amp;#8221;。里面有作者回忆的面试题。其中一题引起了笔者的注意，题目如下：&lt;/p&gt;&lt;p&gt;题目：已知一个数组a[N]，构造一个数组b[N]，构造规则：b[i]=a[0]*a[1]*a[2]...a[N]/a[i];&lt;br /&gt;要求：&lt;br /&gt;　1、不可以使用除法；&lt;br /&gt;　2、时间复杂度为O(n)，空间复杂度为S(0)；&lt;br /&gt;　3、除遍历使用的变量外，不可以使用其它变量；&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;看似简单，想想也废了一番脑筋。&lt;/p&gt;&lt;p&gt;最先想到的是就是原作者想到的方法，代码如下（用的是VB2008）：&amp;nbsp;&lt;/p&gt;&lt;style&gt;.cf1 {color:#000000}.cf2 {color:#FFFFFF}.cf3 {color:#0000FF}&lt;/style&gt;&lt;div style="font-size: 12pt; color: black; font-family: Verdana"&gt;　 &lt;span class="cf3"&gt;Public&lt;/span&gt; &lt;span class="cf3"&gt;Shared&lt;/span&gt; &lt;span class="cf3"&gt;Function&lt;/span&gt; CacuB1(&lt;span class="cf3"&gt;ByVal&lt;/span&gt; A() &lt;span class="cf3"&gt;As&lt;/span&gt; &lt;span class="cf3"&gt;Double&lt;/span&gt;) &lt;span class="cf3"&gt;As&lt;/span&gt; &lt;span class="cf3"&gt;Double&lt;/span&gt;()&lt;br /&gt;&lt;span class="cf3"&gt;Dim&lt;/span&gt; B(A.Length - 1) &lt;span class="cf3"&gt;As&lt;/span&gt; &lt;span class="cf3"&gt;Double&lt;/span&gt;&lt;br /&gt;&lt;span class="cf3"&gt;&lt;/span&gt;&lt;span class="cf3"&gt;Dim&lt;/span&gt; I &lt;span class="cf3"&gt;As&lt;/span&gt; &lt;span class="cf3"&gt;Integer&lt;/span&gt;&lt;br /&gt;&lt;span class="cf3"&gt;&lt;/span&gt;B(0) = 1&lt;br /&gt;&lt;span class="cf3"&gt;For&lt;/span&gt; I = 0 &lt;span class="cf3"&gt;To&lt;/span&gt; A.Length - 1&lt;br /&gt;B(0) *= A(I)&lt;br /&gt;&lt;span class="cf3"&gt;Next&lt;/span&gt;&lt;br /&gt;&lt;span class="cf3"&gt;&lt;/span&gt;&lt;span class="cf3"&gt;For&lt;/span&gt; I = A.Length - 1 &lt;span class="cf3"&gt;To&lt;/span&gt; 0 &lt;span class="cf3"&gt;Step&lt;/span&gt; -1&lt;br /&gt;B(I) = B(0) / A(I)&lt;br /&gt;&lt;span class="cf3"&gt;Next&lt;/span&gt;&lt;br /&gt;&lt;span class="cf3"&gt;&lt;/span&gt;&lt;span class="cf3"&gt;Return&lt;/span&gt; B&lt;br /&gt;&lt;span class="cf3"&gt;End&lt;/span&gt; &lt;span class="cf3"&gt;Function&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;p&gt;&lt;span class="cf3" style="color: #000000"&gt;&lt;/span&gt;&lt;span class="cf3" style="color: #000000"&gt;这个方法还是比较简洁的，没有多余的代码。唯一不符合要求的就是用了除法&lt;/span&gt; &lt;span class="cf3" style="color: #000000"&gt;&lt;/span&gt;&amp;nbsp; &lt;span class="cf3" style="color: #000000"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span class="cf3" style="color: #000000"&gt;那还是老老实实的用最基本的方法，代码如下：&lt;/span&gt; &lt;/p&gt;&lt;div style="font-size: 12pt; color: black; font-family: Verdana"&gt;&lt;span class="cf3"&gt;Public&lt;/span&gt; &lt;span class="cf3"&gt;Shared&lt;/span&gt; &lt;span class="cf3"&gt;Function&lt;/span&gt; CacuB2(&lt;span class="cf3"&gt;ByVal&lt;/span&gt; A() &lt;span class="cf3"&gt;As&lt;/span&gt; &lt;span class="cf3"&gt;Double&lt;/span&gt;) &lt;span class="cf3"&gt;As&lt;/span&gt; &lt;span class="cf3"&gt;Double&lt;/span&gt;()&lt;br /&gt;&lt;span class="cf3"&gt;Dim&lt;/span&gt; B(A.Length - 1) &lt;span class="cf3"&gt;As&lt;/span&gt; &lt;span class="cf3"&gt;Double&lt;/span&gt;&lt;br /&gt;&lt;span class="cf3"&gt;&lt;/span&gt;&lt;span class="cf3"&gt;Dim&lt;/span&gt; I &lt;span class="cf3"&gt;As&lt;/span&gt; &lt;span class="cf3"&gt;Integer&lt;/span&gt;, J &lt;span class="cf3"&gt;As&lt;/span&gt; &lt;span class="cf3"&gt;Integer&lt;/span&gt;&lt;br /&gt;&lt;span class="cf3"&gt;&lt;/span&gt;&lt;span class="cf3"&gt;For&lt;/span&gt; I = 0 &lt;span class="cf3"&gt;To&lt;/span&gt; A.Length - 1&lt;br /&gt;B(I) = 1&lt;br /&gt;&lt;span class="cf3"&gt;For&lt;/span&gt; J = 0 &lt;span class="cf3"&gt;To&lt;/span&gt; A.Length - 1&lt;br /&gt;&lt;span class="cf3"&gt;If&lt;/span&gt; I &amp;lt;&amp;gt; J &lt;span class="cf3"&gt;Then&lt;/span&gt; B(I) *= A(J)&lt;br /&gt;&lt;span class="cf3"&gt;Next&lt;/span&gt;&lt;br /&gt;&lt;span class="cf3"&gt;&lt;/span&gt;&lt;span class="cf3"&gt;Next&lt;/span&gt;&lt;br /&gt;&lt;span class="cf3"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf3"&gt;&lt;/span&gt;&lt;span class="cf3"&gt;Return&lt;/span&gt; B&lt;br /&gt;&lt;span class="cf3"&gt;End&lt;/span&gt; &lt;span class="cf3"&gt;Function&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;p&gt;&lt;span style="color: #000000"&gt;虽然计算量上去了，但没有用除法。不过算法的时间复杂度为O(N*N)，不符合题目要求。而且这种方法比较死板，笔者不推荐。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000"&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000"&gt;想了很久，总是在使用除法和时间复杂度之间没法平衡。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000"&gt;突然，一个念头一闪而过。除法？转一个弯如何？转成减法如何？&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000"&gt;利用公式S/A=10&lt;sup&gt;lgS-lgA&lt;/sup&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000"&gt;于是本题就变成&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000"&gt;S=A(0)*A(1)*A(2)&amp;#8230;&amp;#8230;*A(N)&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #000000"&gt;B(I)=10&lt;sup&gt;lgS-lgA(I)&lt;/sup&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;代码如下：&lt;br /&gt;&lt;div style="font-size: 12pt; color: black; font-family: Verdana"&gt;&lt;span class="cf3"&gt;&lt;/span&gt;&lt;span class="cf3"&gt;Public&lt;/span&gt; &lt;span class="cf3"&gt;Shared&lt;/span&gt; &lt;span class="cf3"&gt;Function&lt;/span&gt; CacuB3(&lt;span class="cf3"&gt;ByVal&lt;/span&gt; A() &lt;span class="cf3"&gt;As&lt;/span&gt; &lt;span class="cf3"&gt;Double&lt;/span&gt;) &lt;span class="cf3"&gt;As&lt;/span&gt; &lt;span class="cf3"&gt;Double&lt;/span&gt;()&lt;br /&gt;&lt;span class="cf3"&gt;Dim&lt;/span&gt; B(A.Length - 1) &lt;span class="cf3"&gt;As&lt;/span&gt; &lt;span class="cf3"&gt;Double&lt;/span&gt;&lt;br /&gt;&lt;span class="cf3"&gt;&lt;/span&gt;&lt;span class="cf3"&gt;Dim&lt;/span&gt; I &lt;span class="cf3"&gt;As&lt;/span&gt; &lt;span class="cf3"&gt;Integer&lt;/span&gt;&lt;br /&gt;&lt;span class="cf3"&gt;&lt;/span&gt;B(0) = 1&lt;br /&gt;&lt;span class="cf3"&gt;For&lt;/span&gt; I = 0 &lt;span class="cf3"&gt;To&lt;/span&gt; A.Length - 1&lt;br /&gt;B(0) *= A(I)&lt;br /&gt;&lt;span class="cf3"&gt;Next&lt;/span&gt;&lt;br /&gt;&lt;span class="cf3"&gt;&lt;/span&gt;&lt;span class="cf3"&gt;For&lt;/span&gt; I = A.Length - 1 &lt;span class="cf3"&gt;To&lt;/span&gt; 0 &lt;span class="cf3"&gt;Step&lt;/span&gt; -1&lt;br /&gt;B(I) = 10 ^ (Math.Log10(B(0)) - Math.Log10(A(I)))&lt;br /&gt;&lt;span class="cf3"&gt;Next&lt;/span&gt;&lt;br /&gt;&lt;span class="cf3"&gt;&lt;/span&gt;&lt;span class="cf3"&gt;Return&lt;/span&gt; B&lt;br /&gt;&lt;span class="cf3"&gt;End&lt;/span&gt; &lt;span class="cf3"&gt;Function&lt;/span&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;符合题目要求了么？符合了，没用除法，时间复杂度也是O(N)。只是效率稍微低了点。&lt;/p&gt;&lt;p&gt;但是效率真的低么？不见得，VS对Log10函数做了优化，虽然低了点，但是可以忽略不计。&lt;/p&gt;&lt;p&gt;利用高中阶段的对数公式，另类的解决了该问题。如果谁还有更好的算法，望不吝赐教。大家互相学习，共同提高。&lt;/p&gt;&lt;/div&gt;&lt;img src="http://www.cnblogs.com/grenet/aggbug/2436384.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/grenet/archive/2012/04/07/2436384.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/grenet/archive/2012/01/10/2317965.html</id><title type="text">在博客中显示不走样的代码</title><summary type="text">在日常的代码开发中。习惯于在自己的代码编辑器里设置自己喜欢的代码字体及颜色。在写博客的过程中，有不可避免的要粘贴一些自己写的代码。问题就来了，往往在博客中提供的代码显示工具显示的代码格式和之前在代码编辑器里就发生了变化。虽不是什么大问题，但总是觉得有点不舒服。 本人用的编辑器是VS系列。一次在无意中将代码复制后，贴到写字板中，发现格式没有发生变化，将文件保存后，用记事本打开，发现是保存为Rtf格式。也就是说，在VS中复制代码，实际内存中保存着该代码的Rtf格式，这样也就是保留了该代码的格式。那么接下来要做的事情就是写一段代码，将该Rtf格式的代码改写成Html格式的代码。由于两种格式之间...</summary><published>2012-01-10T04:20:00Z</published><updated>2012-01-10T04:20:00Z</updated><author><name>万仓一黍</name><uri>http://www.cnblogs.com/grenet/</uri></author><link rel="alternate" href="http://www.cnblogs.com/grenet/archive/2012/01/10/2317965.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/grenet/archive/2012/01/10/2317965.html"/><content type="html">&lt;style&gt;.cf1 {color:#000000}.cf2 {color:#0000FF}.cf3 {color:#00FFFF}.cf4 {color:#00FF00}.cf5 {color:#FF00FF}.cf6 {color:#FF0000}.cf7 {color:#FFFF00}.cf8 {color:#FFFFFF}.cf9 {color:#000080}.cf10 {color:#008080}.cf11 {color:#008000}.cf12 {color:#800080}.cf13 {color:#800000}.cf14 {color:#808000}.cf15 {color:#808080}.cf16 {color:#C0C0C0}&lt;/style&gt;&lt;div style="font-size: 12pt; color: black; font-family: Verdana"&gt;&lt;span class="cf2"&gt;　&lt;/span&gt;　在日常的代码开发中。习惯于在自己的代码编辑器里设置自己喜欢的代码字体及颜色。在写博客的过程中，有不可避免的要粘贴一些自己写的代码。问题就来了，往往在博客中提供的代码显示工具显示的代码格式和之前在代码编辑器里就发生了变化。虽不是什么大问题，但总是觉得有点不舒服。&lt;/div&gt;&lt;div style="font-size: 12pt; color: black; font-family: Verdana"&gt;本人用的编辑器是VS系列。一次在无意中将代码复制后，贴到写字板中，发现格式没有发生变化，将文件保存后，用记事本打开，发现是保存为Rtf格式。也就是说，在VS中复制代码，实际内存中保存着该代码的Rtf格式，这样也就是保留了该代码的格式。那么接下来要做的事情就是写一段代码，将该Rtf格式的代码改写成Html格式的代码。由于两种格式之间相似度还是比较高的，所以写代码也不是一件很难的事。&lt;/div&gt;&lt;div style="font-size: 12pt; color: black; font-family: Verdana"&gt;要注意的是，由于该代码用到了HttpUtility类，因此还得手动添加对System.Web的引用，而不仅仅是添加一句&amp;#8220;Imports System.Web&amp;#8221;。&lt;/div&gt;&lt;div style="font-size: 12pt; color: black; font-family: Verdana"&gt;在调用的时候，启用clsFormatCode.CodeRtfToHtml(Clipboard.GetText(System.Windows.Forms.TextDataFormat.Rtf))这句代码就可以了。&lt;/div&gt;&lt;div style="font-size: 12pt; color: black; font-family: Verdana"&gt;下面是代码，用的是VB2005。&lt;/div&gt;&lt;div style="font-size: 12pt; color: black; font-family: Verdana"&gt;&amp;nbsp;&lt;/div&gt;&lt;div style="font-size: 12pt; color: black; font-family: Verdana"&gt;&lt;span class="cf2"&gt;Imports&lt;/span&gt; System.Web&lt;br /&gt;&lt;br /&gt;&lt;span class="cf2"&gt;Public&lt;/span&gt; &lt;span class="cf2"&gt;Class&lt;/span&gt; clsFormatCode&lt;br /&gt;&lt;span class="cf2"&gt;Private&lt;/span&gt; &lt;span class="cf2"&gt;Shared&lt;/span&gt; &lt;span class="cf2"&gt;Function&lt;/span&gt; CodeRtfToHtml(&lt;span class="cf2"&gt;ByVal&lt;/span&gt; RtfCode &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;String&lt;/span&gt;, &lt;span class="cf2"&gt;ByVal&lt;/span&gt; DefaultFont &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;String&lt;/span&gt;)&lt;br /&gt;&lt;span class="cf2"&gt;Dim&lt;/span&gt; tS &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;New&lt;/span&gt; System.Text.StringBuilder&lt;br /&gt;&lt;br /&gt;RtfCode = RtfCode.Replace(vbNewLine, &lt;span class="cf13"&gt;""&lt;/span&gt;)&lt;br /&gt;&lt;br /&gt;tS.AppendLine(&lt;span class="cf13"&gt;"&amp;lt;style&amp;gt;"&lt;/span&gt;)&lt;br /&gt;&lt;br /&gt;&lt;span class="cf2"&gt;Dim&lt;/span&gt; I &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;Integer&lt;/span&gt;, J &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;Integer&lt;/span&gt;, K &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;Integer&lt;/span&gt; = 1&lt;br /&gt;&lt;br /&gt;I = RtfCode.IndexOf(&lt;span class="cf13"&gt;"{\colortbl;"&lt;/span&gt;) + 11&lt;br /&gt;&lt;br /&gt;&lt;span class="cf2"&gt;Do&lt;/span&gt; &lt;span class="cf2"&gt;While&lt;/span&gt; RtfCode.Chars(I + 1) &amp;lt;&amp;gt; &lt;span class="cf13"&gt;"}"&lt;/span&gt;&lt;br /&gt;&lt;span class="cf13"&gt;&lt;/span&gt;J = RtfCode.IndexOf(&lt;span class="cf13"&gt;";"&lt;/span&gt;, I + 1)&lt;br /&gt;tS.AppendLine(&lt;span class="cf13"&gt;".cf"&lt;/span&gt; &amp;amp; K &amp;amp; &lt;span class="cf13"&gt;" {color:"&lt;/span&gt; &amp;amp; GetColorHex(RtfCode.Substring(I + 1, J - I)) &amp;amp; &lt;span class="cf13"&gt;"}"&lt;/span&gt;)&lt;br /&gt;K += 1&lt;br /&gt;I = J&lt;br /&gt;&lt;span class="cf2"&gt;Loop&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;tS.AppendLine(&lt;span class="cf13"&gt;"&amp;lt;/style&amp;gt;"&lt;/span&gt;)&lt;br /&gt;tS.AppendLine(DefaultFont)&lt;br /&gt;&lt;br /&gt;I = RtfCode.IndexOf(&lt;span class="cf13"&gt;"\fs"&lt;/span&gt;) + 3&lt;br /&gt;K = I&lt;br /&gt;&lt;span class="cf2"&gt;Dim&lt;/span&gt; CurColor &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;String&lt;/span&gt; = &lt;span class="cf13"&gt;"\cf0"&lt;/span&gt;&lt;br /&gt;&lt;span class="cf13"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf13"&gt;&lt;/span&gt;J = RtfCode.IndexOf(&lt;span class="cf13"&gt;"\"&lt;/span&gt;, I)&lt;br /&gt;&lt;span class="cf2"&gt;Do&lt;/span&gt; &lt;span class="cf2"&gt;While&lt;/span&gt; J &amp;lt;&amp;gt; -1&lt;br /&gt;&lt;span class="cf2"&gt;If&lt;/span&gt; RtfCode.Substring(J, 2) = &lt;span class="cf13"&gt;"\\"&lt;/span&gt; &lt;span class="cf2"&gt;Then&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;I = J + 2&lt;br /&gt;&lt;span class="cf2"&gt;ElseIf&lt;/span&gt; RtfCode.Substring(J, 2) = &lt;span class="cf13"&gt;"\{"&lt;/span&gt; &lt;span class="cf2"&gt;Then&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;I = J + 2&lt;br /&gt;&lt;span class="cf2"&gt;ElseIf&lt;/span&gt; RtfCode.Substring(J, 2) = &lt;span class="cf13"&gt;"\}"&lt;/span&gt; &lt;span class="cf2"&gt;Then&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;I = J + 2&lt;br /&gt;&lt;span class="cf2"&gt;ElseIf&lt;/span&gt; RtfCode.Substring(J, 4) = &lt;span class="cf13"&gt;"\par"&lt;/span&gt; &lt;span class="cf2"&gt;Then&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;tS.Append(GetText(RtfCode.Substring(K, J - K), CurColor))&lt;br /&gt;I = J + 5&lt;br /&gt;K = J + 5&lt;br /&gt;tS.Append(&lt;span class="cf13"&gt;"&amp;lt;br /&amp;gt;"&lt;/span&gt; &amp;amp; vbNewLine)&lt;br /&gt;&lt;span class="cf2"&gt;ElseIf&lt;/span&gt; RtfCode.Substring(J, 3) = &lt;span class="cf13"&gt;"\cf"&lt;/span&gt; &lt;span class="cf2"&gt;Then&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;tS.Append(GetText(RtfCode.Substring(K, J - K), CurColor))&lt;br /&gt;K = RtfCode.IndexOf(&lt;span class="cf13"&gt;" "&lt;/span&gt;, J + 1) - J&lt;br /&gt;CurColor = RtfCode.Substring(J, K)&lt;br /&gt;I = J + K + 1&lt;br /&gt;K = I&lt;br /&gt;&lt;span class="cf2"&gt;Else&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;I = J + 1&lt;br /&gt;&lt;span class="cf2"&gt;End&lt;/span&gt; &lt;span class="cf2"&gt;If&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;J = RtfCode.IndexOf(&lt;span class="cf13"&gt;"\"&lt;/span&gt;, I)&lt;br /&gt;&lt;span class="cf2"&gt;Loop&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;tS.Append(GetText(RtfCode.Substring(K, RtfCode.Length - K - 1), CurColor))&lt;br /&gt;&lt;br /&gt;tS.AppendLine(&lt;span class="cf13"&gt;"&amp;lt;/div&amp;gt;"&lt;/span&gt;)&lt;br /&gt;&lt;span class="cf2"&gt;Return&lt;/span&gt; tS.ToString&lt;br /&gt;&lt;span class="cf2"&gt;End&lt;/span&gt; &lt;span class="cf2"&gt;Function&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;span class="cf2"&gt;Public&lt;/span&gt; &lt;span class="cf2"&gt;Shared&lt;/span&gt; &lt;span class="cf2"&gt;Function&lt;/span&gt; CodeRtfToHtml(&lt;span class="cf2"&gt;ByVal&lt;/span&gt; RtfCode &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;String&lt;/span&gt;, &lt;span class="cf2"&gt;ByVal&lt;/span&gt; Font &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;String&lt;/span&gt;, &lt;span class="cf2"&gt;ByVal&lt;/span&gt; FontSize &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;String&lt;/span&gt;)&lt;br /&gt;&lt;span class="cf2"&gt;Return&lt;/span&gt; CodeRtfToHtml(RtfCode, &lt;span class="cf2"&gt;String&lt;/span&gt;.Format(&lt;span class="cf13"&gt;"&amp;lt;div style='color:black;font-family:{0};font-size:{1};'&amp;gt;"&lt;/span&gt;, Font, FontSize))&lt;br /&gt;&lt;span class="cf2"&gt;End&lt;/span&gt; &lt;span class="cf2"&gt;Function&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;span class="cf2"&gt;Public&lt;/span&gt; &lt;span class="cf2"&gt;Shared&lt;/span&gt; &lt;span class="cf2"&gt;Function&lt;/span&gt; CodeRtfToHtml(&lt;span class="cf2"&gt;ByVal&lt;/span&gt; RtfCode &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;String&lt;/span&gt;) &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;String&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;span class="cf2"&gt;Return&lt;/span&gt; CodeRtfToHtml(RtfCode, &lt;span class="cf13"&gt;"&amp;lt;div style='color:black;font-family:Verdana;font-size:12pt;'&amp;gt;"&lt;/span&gt;)&lt;br /&gt;&lt;span class="cf2"&gt;End&lt;/span&gt; &lt;span class="cf2"&gt;Function&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;span class="cf2"&gt;Private&lt;/span&gt; &lt;span class="cf2"&gt;Shared&lt;/span&gt; &lt;span class="cf2"&gt;Function&lt;/span&gt; GetText(&lt;span class="cf2"&gt;ByVal&lt;/span&gt; Text &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;String&lt;/span&gt;, &lt;span class="cf2"&gt;ByVal&lt;/span&gt; CurColor &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;String&lt;/span&gt;) &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;String&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;Text = Text.Replace(&lt;span class="cf13"&gt;"\\"&lt;/span&gt;, &lt;span class="cf13"&gt;"\"&lt;/span&gt;)&lt;br /&gt;Text = Text.Replace(&lt;span class="cf13"&gt;"\{"&lt;/span&gt;, &lt;span class="cf13"&gt;"{"&lt;/span&gt;)&lt;br /&gt;Text = Text.Replace(&lt;span class="cf13"&gt;"\}"&lt;/span&gt;, &lt;span class="cf13"&gt;"}"&lt;/span&gt;)&lt;br /&gt;Text = Text.Replace(&lt;span class="cf13"&gt;"&amp;nbsp; "&lt;/span&gt;, &lt;span class="cf13"&gt;"　"&lt;/span&gt;)&lt;br /&gt;&lt;span class="cf2"&gt;If&lt;/span&gt; CurColor = &lt;span class="cf13"&gt;"\cf0"&lt;/span&gt; &lt;span class="cf2"&gt;Then&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;span class="cf2"&gt;Return&lt;/span&gt; HttpUtility.HtmlEncode(Text)&lt;br /&gt;&lt;span class="cf2"&gt;Else&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;span class="cf2"&gt;Return&lt;/span&gt; &lt;span class="cf13"&gt;"&amp;lt;span class='"&lt;/span&gt; &amp;amp; CurColor.Substring(1) &amp;amp; &lt;span class="cf13"&gt;"'&amp;gt;"&lt;/span&gt; &amp;amp; HttpUtility.HtmlEncode(Text) &amp;amp; &lt;span class="cf13"&gt;"&amp;lt;/span&amp;gt;"&lt;/span&gt;&lt;br /&gt;&lt;span class="cf13"&gt;&lt;/span&gt;&lt;span class="cf2"&gt;End&lt;/span&gt; &lt;span class="cf2"&gt;If&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;span class="cf2"&gt;End&lt;/span&gt; &lt;span class="cf2"&gt;Function&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;span class="cf2"&gt;Private&lt;/span&gt; &lt;span class="cf2"&gt;Shared&lt;/span&gt; &lt;span class="cf2"&gt;Function&lt;/span&gt; GetColorHex(&lt;span class="cf2"&gt;ByVal&lt;/span&gt; ColorText &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;String&lt;/span&gt;) &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;String&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;span class="cf2"&gt;Dim&lt;/span&gt; SR &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;Integer&lt;/span&gt; = ColorText.IndexOf(&lt;span class="cf13"&gt;"\red"&lt;/span&gt;)&lt;br /&gt;&lt;span class="cf2"&gt;Dim&lt;/span&gt; SG &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;Integer&lt;/span&gt; = ColorText.IndexOf(&lt;span class="cf13"&gt;"\green"&lt;/span&gt;)&lt;br /&gt;&lt;span class="cf2"&gt;Dim&lt;/span&gt; SB &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;Integer&lt;/span&gt; = ColorText.IndexOf(&lt;span class="cf13"&gt;"\blue"&lt;/span&gt;)&lt;br /&gt;&lt;br /&gt;&lt;span class="cf2"&gt;Dim&lt;/span&gt; R &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;Integer&lt;/span&gt; = &lt;span class="cf2"&gt;CInt&lt;/span&gt;(ColorText.Substring(SR + 4, SG - SR - 4))&lt;br /&gt;&lt;span class="cf2"&gt;Dim&lt;/span&gt; G &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;Integer&lt;/span&gt; = &lt;span class="cf2"&gt;CInt&lt;/span&gt;(ColorText.Substring(SG + 6, SB - SG - 6))&lt;br /&gt;&lt;span class="cf2"&gt;Dim&lt;/span&gt; B &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;Integer&lt;/span&gt; = &lt;span class="cf2"&gt;CInt&lt;/span&gt;(ColorText.Substring(SB + 5, ColorText.Length - 1 - SB - 5))&lt;br /&gt;&lt;br /&gt;&lt;span class="cf2"&gt;Return&lt;/span&gt; &lt;span class="cf13"&gt;"#"&lt;/span&gt; &amp;amp; R.ToString(&lt;span class="cf13"&gt;"X2"&lt;/span&gt;) &amp;amp; G.ToString(&lt;span class="cf13"&gt;"X2"&lt;/span&gt;) &amp;amp; B.ToString(&lt;span class="cf13"&gt;"X2"&lt;/span&gt;)&lt;br /&gt;&lt;span class="cf2"&gt;End&lt;/span&gt; &lt;span class="cf2"&gt;Function&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;End&lt;/span&gt; &lt;span class="cf2"&gt;Class&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;span class="cf2"&gt;&lt;/span&gt; &lt;img src="http://www.cnblogs.com/grenet/aggbug/2317965.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/grenet/archive/2012/01/10/2317965.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/grenet/archive/2011/12/21/2289014.html</id><title type="text">在VS中利用BackgroundWorker类来实现“仿线程池”</title><summary type="text">在VS编程中，一般遇到比较耗时的操作的时候（例如：从网络上下载文档，文件的IO操作等），如果采用一般的做法，主线程会一直等待操作完成，会遇到界面假死的问题。故在此情况下，合理的做法是采用异步操作和多线程操作。异步操作可以在另开一个线程执行耗时的操作，在主线程上是不等返回，直接操作下一步，从而解决了界面假死的情况。不过，由于异步操作是新开了一个线程，在新开的线程里操作界面元素的时候（例如：在下载文档时显示进度，修改界面上的进度条的数值），会抛出一个线程安全的异常。为了解决这个问题，VS提供了BackgroundWorker类，通过内部封装，提供了一个异步操作，同时又能解决线程安全的问题。Back</summary><published>2011-12-21T07:51:00Z</published><updated>2011-12-21T07:51:00Z</updated><author><name>万仓一黍</name><uri>http://www.cnblogs.com/grenet/</uri></author><link rel="alternate" href="http://www.cnblogs.com/grenet/archive/2011/12/21/2289014.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/grenet/archive/2011/12/21/2289014.html"/><content type="html">&lt;p&gt;&lt;span style="font-size: 12pt; font-family: 宋体"&gt;在&lt;/span&gt;&lt;span style="font-size: 12pt"&gt;VS&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: 宋体"&gt;编程中，一般遇到比较耗时的操作的时候（例如：从网络上下载文档，文件的&lt;/span&gt;&lt;span style="font-size: 12pt"&gt;IO&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: 宋体"&gt;操作等），如果采用一般的做法，主线程会一直等待操作完成，会遇到界面假死的问题。故在此情况下，合理的做法是采用异步操作和多线程操作。异步操作可以在另开一个线程执行耗时的操作，在主线程上是不等返回，直接操作下一步，从而解决了界面假死的情况。不过，由于异步操作是新开了一个线程，在新开的线程里操作界面元素的时候（例如：在下载文档时显示进度，修改界面上的进度条的数值），会抛出一个线程安全的异常。为了解决这个问题，&lt;/span&gt;&lt;span style="font-size: 12pt"&gt;VS&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: 宋体"&gt;提供了&lt;/span&gt;&lt;span style="font-size: 12pt"&gt;BackgroundWorker&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: 宋体"&gt;类，通过内部封装，提供了一个异步操作，同时又能解决线程安全的问题。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt"&gt;BackgroundWorker&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: 宋体"&gt;类提供了二个方法和三个事件来实现异步操作的线程安全的问题。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; font-family: 宋体"&gt;首先是&lt;font face="Verdana"&gt;&lt;span style="font-size: 12pt"&gt;RunWorkerAsync&lt;/span&gt;&lt;/font&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: 宋体"&gt;方法，告诉系统现在要新开一个线程来执行一个异步操作。该方法会引发&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;DoWork&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: 宋体"&gt;事件，在&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;DoWork&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: 宋体"&gt;事件内，执行一个耗时的操作。此时，该事件中的代码是执行在另一个线程中。如果在该事件中，尝试操作主界面上的元素的时候，立马抛出一个线程安全的异常。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; font-family: 宋体"&gt;那该如何操作主界面的元素呢？在&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;DoWork&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: 宋体"&gt;事件中调用&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;ReportProgress&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: 宋体"&gt;方法，引发&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;ProgressChanged&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: 宋体"&gt;事件，并通过&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;userState&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: 宋体"&gt;参数把参数传递过去。&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;Progresschanged&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: 宋体"&gt;事件是和主界面在一个线程里。在该事件里，根据传递来的参数操作主界面上的元素就不会有线程安全的问题。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; font-family: 宋体"&gt;在执行完&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;DoWork&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: 宋体"&gt;事件中的代码后，会调用&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;RunWorkerCompleted&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: 宋体"&gt;事件，通知主线程，异步操作已经完成。同样该事件也是和主界面在同一个线程里，也同样能操作主界面的元素而不会引发线程安全的异常。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; font-family: 宋体"&gt;如果现在有一个任务是下载&lt;/span&gt;&lt;span style="font-size: 12pt"&gt;200&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: 宋体"&gt;个网页。该如何操作？一个接着一个下载，利用类可以解决界面假死和线程安全的问题。不过效率也太低了一点。如果利用多线程同时下载&lt;/span&gt;&lt;span style="font-size: 12pt"&gt;200&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: 宋体"&gt;个网页，那么可能超过系统的负担，造成效率的低下。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; font-family: 宋体"&gt;&amp;#8220;线程池&amp;#8221;的概念应运而生。在线程池里准备好一定数量的线程，例如&lt;/span&gt;&lt;span style="font-size: 12pt"&gt;50&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: 宋体"&gt;个线程。以上面的例子，&lt;/span&gt;&lt;span style="font-size: 12pt"&gt;200&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: 宋体"&gt;个下载网页任务。由于只有&lt;/span&gt;&lt;span style="font-size: 12pt"&gt;50&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: 宋体"&gt;个线程。那么&lt;/span&gt;&lt;span style="font-size: 12pt"&gt;50&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: 宋体"&gt;个下载网页任务先执行，剩下的&lt;/span&gt;&lt;span style="font-size: 12pt"&gt;150&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: 宋体"&gt;个下载网页任务先暂时挂起。等到某一个线程执行完任务后，再执行挂起的任务。直到所有的任务都完成。&amp;#8220;线程池&amp;#8221;的好处是严格控制线程的数量，不给系统造成太大的负担。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; font-family: 宋体"&gt;根据&amp;#8220;线程池&amp;#8221;的思想。自己编写了一个类。类的全部代码附在本文的最后。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; font-family: 宋体"&gt;接下来，阐述一下该类的具体实现。类的名称为&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;clsWorkPool&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; font-family: 宋体"&gt;首先，&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;clsWorkPool&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: 宋体"&gt;类定义一个委托，该委托来完成&amp;#8220;工作&amp;#8221;。该类只负责&amp;#8220;线程池&amp;#8221;的实现与调度，不实现具体的工作。故用委托比较合适。委托的定义如下：&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 宋体"&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;Public Delegate Function&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt; WorkDelegate(&lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;ByVal&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt; Param &lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;As Object&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;) &lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;As Object&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 宋体"&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; font-family: 宋体"&gt;类&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;clsWorkPool&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: 宋体"&gt;的构造函数代码如下&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 宋体"&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;Public Sub New&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;(&lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;ByVal&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt; ThreadCount &lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;As Integer)&lt;/span&gt; &lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;_ThreadCount = ThreadCount&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;ReDim&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt; _BgWorker(ThreadCount - 1)&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;Dim&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt; I &lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;As Integer&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;For&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt; I = 0 &lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;To&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt; ThreadCount - 1&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;_BgWorker(I) = &lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;New&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt; BackgroundWorker&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;AddHandler&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt; _BgWorker(I).DoWork, &lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;AddressOf&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt; RunWorkerStart&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;AddHandler&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt; _BgWorker(I).RunWorkerCompleted, &lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;AddressOf&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt; RunWorkerCompleted&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;Next&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;_Work = &lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;New&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt; Queue(&lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;Of&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt; clsWork)&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;_ID = 0&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;_HadComplete=0&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;_ThreadLock = &lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;New Object&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;End Sub&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt"&gt;根据传递进来的参数&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;_ThreadCount&lt;/span&gt;&lt;span style="font-size: 12pt"&gt;，来创立&amp;#8220;线程池&amp;#8221;&amp;#8212;&amp;#8212;&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;BackgroundWorker&lt;/span&gt;&lt;span style="font-size: 12pt"&gt;类的数组。该数组内的数量决定了线程池中线程的数量。&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;_Work&lt;/span&gt;&lt;span style="font-size: 12pt"&gt;是一个队列对象，将暂时不能执行的任务，挂起到队列中，等到有空闲的线程的时候再执行。&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;_ThreadLock&lt;/span&gt;&lt;span style="font-size: 12pt"&gt;是一个线程安全锁。防止多线程操作，修改参数，互相影响。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt"&gt;类&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;clsWorkPool&lt;/span&gt;&lt;span style="font-size: 12pt"&gt;的添加任务的代码&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;Public Function&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt; DoWork(&lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;ByVal&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt; Work &lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;As&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt; WorkDelegate, &lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;ByVal&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt; Param &lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;As Object&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;) &lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;As Integer&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;SyncLock&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt; _ThreadLock&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;Dim&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt; I &lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;As Integer&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;, J &lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;As Boolean&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;_ID += 1&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;J = &lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;False&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;Dim&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt; tWork As &lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;New&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt; clsWork(Work, Param, _ID)&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;For&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt; I = 0 &lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;To&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt; _ThreadCount - 1&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;If&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt; _BgWorker(I).IsBusy = &lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;False&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt; &lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;Then&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;RaiseWorkStart(_BgWorker(I), tWork)&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;J = &lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;True&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;Exit For&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;End If&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;Next&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;If&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt; J = &lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;False&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt; &lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;Then&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;_Work.Enqueue(tWork)&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;RaiseEvent&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt; WorkSuspend(&lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;Me&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;, &lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;New&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt; WorkStartSuspendEventArgs(_ID))&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;End If&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;DoWork = _ID&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;End SyncLock&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;End Function&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt"&gt;由于牵涉到多线程异步操作，故在代码的开始和结束添加线程锁。首先，根据传递进来的参数，生成一个包含任务各种参数的一个类&lt;/span&gt;&lt;font face="Verdana"&gt;&lt;span style="font-size: 12pt"&gt;clsWork&lt;/span&gt;&lt;/font&gt;&lt;span style="font-size: 12pt"&gt;。然后遍历线程池，看有没有空闲的线程。如果有空闲的线程，调用&lt;/span&gt;&lt;font face="Verdana"&gt;&lt;span style="font-size: 12pt"&gt;RaiseWorkStart(_BgWorker(I), tWork)&lt;/span&gt;&lt;/font&gt;&lt;span style="font-size: 12pt"&gt;方法，通过空闲的线程来完成任务。在&lt;/span&gt;&lt;font face="Verdana"&gt;&lt;span style="font-size: 12pt"&gt;RaiseWorkStart(_BgWorker(I), tWork)方法中，有两句话，一是调用BackgroundWorker类的实例Work的RunWorkerAsync方法，启用辅助线程完成工作；一是引发WorkStart事件，通知主线程该工作已经启动。如果没有空闲的线程，则将该任务添加到队列_Work中，等待空闲的线程，并引发WorkSuspend事件，通知主线程该工作暂时挂起。&lt;/span&gt;&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt"&gt;在调用Work的RunWorkerAsync方法之后，会引发Work的DoWork的事件，即下面的RunWorkerStart方法，通过调用clsWork类的Work委托的Invoke方法，来完成该任务，并将返回值写回。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;Private Sub&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt; RunWorkerStart(&lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;ByVal&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt; sender &lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;As Object&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;, &lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;ByVal&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt; e &lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;As&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt; DoWorkEventArgs)&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;Dim&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt; T &lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;As&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt; clsWork = &lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;CType&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;(e.Argument, clsWork)&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;e.Result = &lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;New&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt; clsResult(T.ID, T.Work.Invoke(T.Param))&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;End Sub&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt"&gt;在执行完上面的函数，会引发Work的RunWorkerCompleted事件，即下面的RunWorkerCompleted方法。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;Private Sub&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt; RunWorkerCompleted(&lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;ByVal&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt; sender &lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;As Object&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;, &lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;ByVal&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt; e &lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;As&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt; RunWorkerCompletedEventArgs)&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;SyncLock&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt; _ThreadLock&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;Dim&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt; T &lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;As&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt; clsResult = &lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;CType&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;(e.Result, clsResult)&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;RaiseEvent&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt; WorkComplete(&lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;Me&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;, &lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;New&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt; WorkCompleteEventArgs(T.ID, T.Result))&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;_HadComplete += 1&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;If&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt; _Work.Count &amp;gt; 0 &lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;Then&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;Dim&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt; tW &lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;As&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt; BackgroundWorker = &lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;CType&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;(sender, BackgroundWorker)&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;If&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt; tW.IsBusy = &lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;False Then &lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;RaiseWorkStart(tW, _Work.Dequeue)&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;Else&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;If&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt; _HadComplete &amp;gt;= _ID &lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;Then&amp;nbsp;&lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;RaiseEvent&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt; AllWorkComplete(&lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;Me&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;, &lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;New&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt; EventArgs)&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;End If&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;End SyncLock&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; color: #0000ff; font-family: Verdana"&gt;End Sub&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt"&gt;首先引发WorkComplete事件，告诉主线程，该任务已经完成。将完成的任务数加1。同时，检查挂起的任务数，若还有挂起的任务，则调用RaiseWorkStart方法，重新启动队列中的一个新的任务。若没有挂起的任务，则检查完成的任务数，任务数达到一定的数量，则说明所有的任务都完成了，则引发AllWorkComplete事件。告知主线程，所有的任务都已经完成。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt"&gt;下面举一个例子，来展示该类的实际效果&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt"&gt;在Form上，放一个ListBox和Button。代码如下&lt;/span&gt;&lt;/p&gt;&lt;style&gt;.cf1 {color:#000000}.cf2 {color:#0000FF}.cf3 {color:#00FFFF}.cf4 {color:#00FF00}.cf5 {color:#FF00FF}.cf6 {color:#FF0000}.cf7 {color:#FFFF00}.cf8 {color:#FFFFFF}.cf9 {color:#000080}.cf10 {color:#008080}.cf11 {color:#008000}.cf12 {color:#800080}.cf13 {color:#800000}.cf14 {color:#808000}.cf15 {color:#808080}.cf16 {color:#C0C0C0}&lt;/style&gt;&lt;div style="font-size: 12pt; color: black; font-family: Verdana"&gt;&lt;span class="cf2"&gt;Public&lt;/span&gt; &lt;span class="cf2"&gt;Class&lt;/span&gt; Form1&lt;br /&gt;&lt;span class="cf2"&gt;Private&lt;/span&gt; &lt;span class="cf2"&gt;WithEvents&lt;/span&gt; _Pool &lt;span class="cf2"&gt;As&lt;/span&gt; clsWorkPool&lt;br /&gt;&lt;br /&gt;&lt;span class="cf2"&gt;Private&lt;/span&gt; &lt;span class="cf2"&gt;Sub&lt;/span&gt; Button1_Click(&lt;span class="cf2"&gt;ByVal&lt;/span&gt; sender &lt;span class="cf2"&gt;As&lt;/span&gt; System.Object, &lt;span class="cf2"&gt;ByVal&lt;/span&gt; e &lt;span class="cf2"&gt;As&lt;/span&gt; System.EventArgs) &lt;span class="cf2"&gt;Handles&lt;/span&gt; Button1.Click&lt;br /&gt;_Pool = &lt;span class="cf2"&gt;New&lt;/span&gt; clsWorkPool(5)&lt;br /&gt;&lt;br /&gt;&lt;span class="cf2"&gt;Dim&lt;/span&gt; I &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;Integer&lt;/span&gt;, J &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;Integer&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;span class="cf2"&gt;For&lt;/span&gt; I = 2008 &lt;span class="cf2"&gt;To&lt;/span&gt; 2011&lt;br /&gt;&lt;span class="cf2"&gt;For&lt;/span&gt; J = 1 &lt;span class="cf2"&gt;To&lt;/span&gt; 12&lt;br /&gt;_Pool.DoWork(&lt;span class="cf2"&gt;AddressOf&lt;/span&gt; GetWebString, I &amp;amp; &lt;span class="cf13"&gt;"-"&lt;/span&gt; &amp;amp; J)&lt;br /&gt;&lt;span class="cf2"&gt;Next&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;span class="cf2"&gt;Next&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;span class="cf2"&gt;End&lt;/span&gt; &lt;span class="cf2"&gt;Sub&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;span class="cf2"&gt;Public&lt;/span&gt; &lt;span class="cf2"&gt;Function&lt;/span&gt; GetWebString(&lt;span class="cf2"&gt;ByVal&lt;/span&gt; Url &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;Object&lt;/span&gt;) &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;Object&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;span class="cf2"&gt;Dim&lt;/span&gt; _Web &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;New&lt;/span&gt; Net.WebClient&lt;br /&gt;&lt;span class="cf2"&gt;Dim&lt;/span&gt; _UrlParam() &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;String&lt;/span&gt; = &lt;span class="cf2"&gt;CType&lt;/span&gt;(Url, &lt;span class="cf2"&gt;String&lt;/span&gt;).Split(&lt;span class="cf13"&gt;"-"&lt;/span&gt;)&lt;br /&gt;&lt;span class="cf2"&gt;Dim&lt;/span&gt; _Url &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;String&lt;/span&gt; = &lt;span class="cf2"&gt;String&lt;/span&gt;.Format(&lt;span class="cf13"&gt;"http://www.istartedsomething.com/bingimages/?m={0}&amp;amp;y={1}"&lt;/span&gt;, _UrlParam(0), _UrlParam(1))&lt;br /&gt;&lt;br /&gt;&lt;span class="cf2"&gt;Dim&lt;/span&gt; str &lt;span class="cf2"&gt;As&lt;/span&gt; IO.Stream&lt;br /&gt;&lt;br /&gt;str = _Web.OpenRead(_Url)&lt;br /&gt;&lt;span class="cf2"&gt;Dim&lt;/span&gt; read &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;New&lt;/span&gt; IO.StreamReader(str, System.Text.Encoding.GetEncoding(&lt;span class="cf13"&gt;"GB2312"&lt;/span&gt;))&lt;br /&gt;&lt;span class="cf2"&gt;Dim&lt;/span&gt; Text &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;String&lt;/span&gt; = read.ReadToEnd()&lt;br /&gt;&lt;br /&gt;&lt;span class="cf2"&gt;Return&lt;/span&gt; Url&lt;br /&gt;&lt;span class="cf2"&gt;End&lt;/span&gt; &lt;span class="cf2"&gt;Function&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;span class="cf2"&gt;Private&lt;/span&gt; &lt;span class="cf2"&gt;Sub&lt;/span&gt; AddListText(&lt;span class="cf2"&gt;ByVal&lt;/span&gt; Text &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;String&lt;/span&gt;)&lt;br /&gt;ListBox1.Items.Add(Text)&lt;br /&gt;&lt;span class="cf2"&gt;End&lt;/span&gt; &lt;span class="cf2"&gt;Sub&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;span class="cf2"&gt;Private&lt;/span&gt; &lt;span class="cf2"&gt;Sub&lt;/span&gt; _Pool_AllWorkComplete(&lt;span class="cf2"&gt;ByVal&lt;/span&gt; Sender &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;Object&lt;/span&gt;, &lt;span class="cf2"&gt;ByVal&lt;/span&gt; E &lt;span class="cf2"&gt;As&lt;/span&gt; System.EventArgs) &lt;span class="cf2"&gt;Handles&lt;/span&gt; _Pool.AllWorkComplete&lt;br /&gt;AddListText(&lt;span class="cf2"&gt;String&lt;/span&gt;.Format(&lt;span class="cf13"&gt;"All Work Complete!!!"&lt;/span&gt;))&lt;br /&gt;&lt;span class="cf2"&gt;End&lt;/span&gt; &lt;span class="cf2"&gt;Sub&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;span class="cf2"&gt;Private&lt;/span&gt; &lt;span class="cf2"&gt;Sub&lt;/span&gt; _Pool_WorkComplete(&lt;span class="cf2"&gt;ByVal&lt;/span&gt; Sender &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;Object&lt;/span&gt;, &lt;span class="cf2"&gt;ByVal&lt;/span&gt; E &lt;span class="cf2"&gt;As&lt;/span&gt; WorkCompleteEventArgs) &lt;span class="cf2"&gt;Handles&lt;/span&gt; _Pool.WorkComplete&lt;br /&gt;AddListText(&lt;span class="cf2"&gt;String&lt;/span&gt;.Format(&lt;span class="cf13"&gt;"Work {0} is Complete,The result is {1}"&lt;/span&gt;, E.ID, E.Result.ToString))&lt;br /&gt;&lt;span class="cf2"&gt;End&lt;/span&gt; &lt;span class="cf2"&gt;Sub&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;span class="cf2"&gt;Private&lt;/span&gt; &lt;span class="cf2"&gt;Sub&lt;/span&gt; _Pool_WorkStart(&lt;span class="cf2"&gt;ByVal&lt;/span&gt; Sender &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;Object&lt;/span&gt;, &lt;span class="cf2"&gt;ByVal&lt;/span&gt; E &lt;span class="cf2"&gt;As&lt;/span&gt; WorkStartSuspendEventArgs) &lt;span class="cf2"&gt;Handles&lt;/span&gt; _Pool.WorkStart&lt;br /&gt;AddListText(&lt;span class="cf2"&gt;String&lt;/span&gt;.Format(&lt;span class="cf13"&gt;"Work {0} is Start"&lt;/span&gt;, E.ID))&lt;br /&gt;&lt;span class="cf2"&gt;End&lt;/span&gt; &lt;span class="cf2"&gt;Sub&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;span class="cf2"&gt;Private&lt;/span&gt; &lt;span class="cf2"&gt;Sub&lt;/span&gt; _Pool_WorkSuspend(&lt;span class="cf2"&gt;ByVal&lt;/span&gt; Sender &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;Object&lt;/span&gt;, &lt;span class="cf2"&gt;ByVal&lt;/span&gt; E &lt;span class="cf2"&gt;As&lt;/span&gt; WorkStartSuspendEventArgs) &lt;span class="cf2"&gt;Handles&lt;/span&gt; _Pool.WorkSuspend&lt;br /&gt;AddListText(&lt;span class="cf2"&gt;String&lt;/span&gt;.Format(&lt;span class="cf13"&gt;"Work {0} is Suspend"&lt;/span&gt;, E.ID))&lt;br /&gt;&lt;span class="cf2"&gt;End&lt;/span&gt; &lt;span class="cf2"&gt;Sub&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;End&lt;/span&gt; &lt;span class="cf2"&gt;Class&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;/div&gt;&lt;p&gt;&lt;/span&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;&lt;span style="font-size: 12pt"&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt"&gt;在按下Button1之后，先初始化线程池中5个线程。然后添加了48个下载网页任务，每个任务调用GetWebString函数，该函数符合Work的委托。由于只有5个线程，故有43个线程被挂起，直到有任务完成后，再执行挂起的任务。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt"&gt;下面，贴二张截图&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt"&gt;&lt;img height="384" alt="" src="http://images.cnblogs.com/cnblogs_com/grenet/G-1.JPG" width="484" border="0" /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt"&gt;&lt;img height="384" alt="" src="http://images.cnblogs.com/cnblogs_com/grenet/G-2.JPG" width="484" border="0" longdesc="" /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;/span&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt"&gt;通过修改线程池的线程数，发现，在不同的线程数下，效果不完全一样。线程为1的时候，此时只有一个辅助线程，和单线程无异，完成48个任务一共耗时88.6秒。线程数为20的时候，效果比较好，完成48个任务一共耗时26.2秒。线程数为50的时候，此时，所有的任务都没有挂起，直接运行。完成这些任务，一共耗时44.1秒，反而不如20个线程的时候，可见，在下载的任务的时候时，线程数不宜过多。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt"&gt;还有一点说明的是，在例子中，48个任务执行的是同一种任务&amp;#8212;&amp;#8212;调用的同一个函数。实际情况是可以调用不同任务&amp;#8212;&amp;#8212;调用不同的函数，只要这些函数满足同一种委托。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size: 12pt; font-family: Verdana"&gt;附：&amp;#8220;线程池&amp;#8221;的全部代码。代码格式修正于2012年1月6日&lt;/span&gt;&lt;/p&gt;&lt;style&gt;.cf1 {color:#000000}.cf2 {color:#0000FF}.cf3 {color:#00FFFF}.cf4 {color:#00FF00}.cf5 {color:#FF00FF}.cf6 {color:#FF0000}.cf7 {color:#FFFF00}.cf8 {color:#FFFFFF}.cf9 {color:#000080}.cf10 {color:#008080}.cf11 {color:#008000}.cf12 {color:#800080}.cf13 {color:#800000}.cf14 {color:#808000}.cf15 {color:#808080}.cf16 {color:#C0C0C0}&lt;/style&gt;&lt;div style="font-size: 12pt; color: black; font-family: Verdana"&gt;&lt;span class="cf2"&gt;Imports&lt;/span&gt; System.ComponentModel&lt;br /&gt;&lt;span class="cf2"&gt;Public&lt;/span&gt; &lt;span class="cf2"&gt;Class&lt;/span&gt; clsWorkPool&lt;br /&gt;&lt;span class="cf2"&gt;Public&lt;/span&gt; &lt;span class="cf2"&gt;Delegate&lt;/span&gt; &lt;span class="cf2"&gt;Function&lt;/span&gt; WorkDelegate(&lt;span class="cf2"&gt;ByVal&lt;/span&gt; Param &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;Object&lt;/span&gt;) &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;Object&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;span class="cf2"&gt;Private&lt;/span&gt; &lt;span class="cf2"&gt;Class&lt;/span&gt; clsWork&lt;br /&gt;&lt;span class="cf2"&gt;Public&lt;/span&gt; Work &lt;span class="cf2"&gt;As&lt;/span&gt; WorkDelegate&lt;br /&gt;&lt;span class="cf2"&gt;Public&lt;/span&gt; Param &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;Object&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;span class="cf2"&gt;Public&lt;/span&gt; ID &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;Integer&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;span class="cf2"&gt;Public&lt;/span&gt; &lt;span class="cf2"&gt;Sub&lt;/span&gt; &lt;span class="cf2"&gt;New&lt;/span&gt;(&lt;span class="cf2"&gt;ByVal&lt;/span&gt; Work &lt;span class="cf2"&gt;As&lt;/span&gt; WorkDelegate, &lt;span class="cf2"&gt;ByVal&lt;/span&gt; Param &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;Object&lt;/span&gt;, &lt;span class="cf2"&gt;ByVal&lt;/span&gt; ID &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;Integer&lt;/span&gt;)&lt;br /&gt;&lt;span class="cf2"&gt;Me&lt;/span&gt;.Work = Work&lt;br /&gt;&lt;span class="cf2"&gt;Me&lt;/span&gt;.Param = Param&lt;br /&gt;&lt;span class="cf2"&gt;Me&lt;/span&gt;.ID = ID&lt;br /&gt;&lt;span class="cf2"&gt;End&lt;/span&gt; &lt;span class="cf2"&gt;Sub&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;span class="cf2"&gt;End&lt;/span&gt; &lt;span class="cf2"&gt;Class&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;span class="cf2"&gt;Private&lt;/span&gt; &lt;span class="cf2"&gt;Class&lt;/span&gt; clsResult&lt;br /&gt;&lt;span class="cf2"&gt;Public&lt;/span&gt; Result &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;Object&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;span class="cf2"&gt;Public&lt;/span&gt; ID &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;Integer&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;span class="cf2"&gt;Public&lt;/span&gt; &lt;span class="cf2"&gt;Sub&lt;/span&gt; &lt;span class="cf2"&gt;New&lt;/span&gt;(&lt;span class="cf2"&gt;ByVal&lt;/span&gt; ID &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;Integer&lt;/span&gt;, &lt;span class="cf2"&gt;ByVal&lt;/span&gt; Result &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;Object&lt;/span&gt;)&lt;br /&gt;&lt;span class="cf2"&gt;Me&lt;/span&gt;.ID = ID&lt;br /&gt;&lt;span class="cf2"&gt;Me&lt;/span&gt;.Result = Result&lt;br /&gt;&lt;span class="cf2"&gt;End&lt;/span&gt; &lt;span class="cf2"&gt;Sub&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;span class="cf2"&gt;End&lt;/span&gt; &lt;span class="cf2"&gt;Class&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;span class="cf2"&gt;Private&lt;/span&gt; _ThreadCount &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;Integer&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;span class="cf2"&gt;Private&lt;/span&gt; _BgWorker() &lt;span class="cf2"&gt;As&lt;/span&gt; BackgroundWorker&lt;br /&gt;&lt;span class="cf2"&gt;Private&lt;/span&gt; _ID &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;Integer&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;span class="cf2"&gt;Private&lt;/span&gt; _HadComplete &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;Integer&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;span class="cf2"&gt;Private&lt;/span&gt; _Work &lt;span class="cf2"&gt;As&lt;/span&gt; Queue(&lt;span class="cf2"&gt;Of&lt;/span&gt; clsWork)&lt;br /&gt;&lt;span class="cf2"&gt;Private&lt;/span&gt; _ThreadLock &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;Object&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;span class="cf2"&gt;Public&lt;/span&gt; &lt;span class="cf2"&gt;Event&lt;/span&gt; WorkStart(&lt;span class="cf2"&gt;ByVal&lt;/span&gt; Sender &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;Object&lt;/span&gt;, &lt;span class="cf2"&gt;ByVal&lt;/span&gt; E &lt;span class="cf2"&gt;As&lt;/span&gt; WorkStartSuspendEventArgs)&lt;br /&gt;&lt;span class="cf2"&gt;Public&lt;/span&gt; &lt;span class="cf2"&gt;Event&lt;/span&gt; WorkComplete(&lt;span class="cf2"&gt;ByVal&lt;/span&gt; Sender &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;Object&lt;/span&gt;, &lt;span class="cf2"&gt;ByVal&lt;/span&gt; E &lt;span class="cf2"&gt;As&lt;/span&gt; WorkCompleteEventArgs)&lt;br /&gt;&lt;span class="cf2"&gt;Public&lt;/span&gt; &lt;span class="cf2"&gt;Event&lt;/span&gt; WorkSuspend(&lt;span class="cf2"&gt;ByVal&lt;/span&gt; Sender &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;Object&lt;/span&gt;, &lt;span class="cf2"&gt;ByVal&lt;/span&gt; E &lt;span class="cf2"&gt;As&lt;/span&gt; WorkStartSuspendEventArgs)&lt;br /&gt;&lt;span class="cf2"&gt;Public&lt;/span&gt; &lt;span class="cf2"&gt;Event&lt;/span&gt; AllWorkComplete(&lt;span class="cf2"&gt;ByVal&lt;/span&gt; Sender &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;Object&lt;/span&gt;, &lt;span class="cf2"&gt;ByVal&lt;/span&gt; E &lt;span class="cf2"&gt;As&lt;/span&gt; EventArgs)&lt;br /&gt;&lt;br /&gt;&lt;span class="cf2"&gt;Public&lt;/span&gt; &lt;span class="cf2"&gt;Sub&lt;/span&gt; &lt;span class="cf2"&gt;New&lt;/span&gt;()&lt;br /&gt;&lt;span class="cf2"&gt;Me&lt;/span&gt;.New(50)&lt;br /&gt;&lt;span class="cf2"&gt;End&lt;/span&gt; &lt;span class="cf2"&gt;Sub&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;span class="cf2"&gt;Public&lt;/span&gt; &lt;span class="cf2"&gt;Sub&lt;/span&gt; &lt;span class="cf2"&gt;New&lt;/span&gt;(&lt;span class="cf2"&gt;ByVal&lt;/span&gt; ThreadCount &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;Integer&lt;/span&gt;)&lt;br /&gt;_ThreadCount = ThreadCount&lt;br /&gt;&lt;span class="cf2"&gt;ReDim&lt;/span&gt; _BgWorker(ThreadCount - 1)&lt;br /&gt;&lt;span class="cf2"&gt;Dim&lt;/span&gt; I &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;Integer&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;span class="cf2"&gt;For&lt;/span&gt; I = 0 &lt;span class="cf2"&gt;To&lt;/span&gt; ThreadCount - 1&lt;br /&gt;_BgWorker(I) = &lt;span class="cf2"&gt;New&lt;/span&gt; BackgroundWorker&lt;br /&gt;&lt;span class="cf2"&gt;AddHandler&lt;/span&gt; _BgWorker(I).DoWork, &lt;span class="cf2"&gt;AddressOf&lt;/span&gt; RunWorkerStart&lt;br /&gt;&lt;span class="cf2"&gt;AddHandler&lt;/span&gt; _BgWorker(I).RunWorkerCompleted, &lt;span class="cf2"&gt;AddressOf&lt;/span&gt; RunWorkerCompleted&lt;br /&gt;&lt;span class="cf2"&gt;Next&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;_Work = &lt;span class="cf2"&gt;New&lt;/span&gt; Queue(&lt;span class="cf2"&gt;Of&lt;/span&gt; clsWork)&lt;br /&gt;_ID = 0&lt;br /&gt;_HadComplete = 0&lt;br /&gt;_ThreadLock = &lt;span class="cf2"&gt;New&lt;/span&gt; &lt;span class="cf2"&gt;Object&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;span class="cf2"&gt;End&lt;/span&gt; &lt;span class="cf2"&gt;Sub&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;span class="cf2"&gt;Public&lt;/span&gt; &lt;span class="cf2"&gt;Function&lt;/span&gt; DoWork(&lt;span class="cf2"&gt;ByVal&lt;/span&gt; Work &lt;span class="cf2"&gt;As&lt;/span&gt; WorkDelegate, &lt;span class="cf2"&gt;ByVal&lt;/span&gt; Param &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;Object&lt;/span&gt;) &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;Integer&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;span class="cf2"&gt;SyncLock&lt;/span&gt; _ThreadLock&lt;br /&gt;&lt;span class="cf2"&gt;Dim&lt;/span&gt; I &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;Integer&lt;/span&gt;, J &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;Boolean&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;_ID += 1&lt;br /&gt;J = &lt;span class="cf2"&gt;False&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;span class="cf2"&gt;Dim&lt;/span&gt; tWork &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;New&lt;/span&gt; clsWork(Work, Param, _ID)&lt;br /&gt;&lt;span class="cf2"&gt;For&lt;/span&gt; I = 0 &lt;span class="cf2"&gt;To&lt;/span&gt; _ThreadCount - 1&lt;br /&gt;&lt;span class="cf2"&gt;If&lt;/span&gt; _BgWorker(I).IsBusy = &lt;span class="cf2"&gt;False&lt;/span&gt; &lt;span class="cf2"&gt;Then&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;RaiseWorkStart(_BgWorker(I), tWork)&lt;br /&gt;J = &lt;span class="cf2"&gt;True&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;span class="cf2"&gt;Exit&lt;/span&gt; &lt;span class="cf2"&gt;For&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;span class="cf2"&gt;End&lt;/span&gt; &lt;span class="cf2"&gt;If&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;span class="cf2"&gt;Next&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;span class="cf2"&gt;If&lt;/span&gt; J = &lt;span class="cf2"&gt;False&lt;/span&gt; &lt;span class="cf2"&gt;Then&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;_Work.Enqueue(tWork)&lt;br /&gt;&lt;span class="cf2"&gt;RaiseEvent&lt;/span&gt; WorkSuspend(&lt;span class="cf2"&gt;Me&lt;/span&gt;, &lt;span class="cf2"&gt;New&lt;/span&gt; WorkStartSuspendEventArgs(_ID))&lt;br /&gt;&lt;span class="cf2"&gt;End&lt;/span&gt; &lt;span class="cf2"&gt;If&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;DoWork = _ID&lt;br /&gt;&lt;span class="cf2"&gt;End&lt;/span&gt; &lt;span class="cf2"&gt;SyncLock&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;span class="cf2"&gt;End&lt;/span&gt; &lt;span class="cf2"&gt;Function&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;span class="cf2"&gt;Private&lt;/span&gt; &lt;span class="cf2"&gt;Sub&lt;/span&gt; RaiseWorkStart(&lt;span class="cf2"&gt;ByVal&lt;/span&gt; Worker &lt;span class="cf2"&gt;As&lt;/span&gt; BackgroundWorker, &lt;span class="cf2"&gt;ByVal&lt;/span&gt; Work &lt;span class="cf2"&gt;As&lt;/span&gt; clsWork)&lt;br /&gt;Worker.RunWorkerAsync(Work)&lt;br /&gt;&lt;span class="cf2"&gt;RaiseEvent&lt;/span&gt; WorkStart(&lt;span class="cf2"&gt;Me&lt;/span&gt;, &lt;span class="cf2"&gt;New&lt;/span&gt; WorkStartSuspendEventArgs(Work.ID))&lt;br /&gt;&lt;span class="cf2"&gt;End&lt;/span&gt; &lt;span class="cf2"&gt;Sub&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;span class="cf2"&gt;Private&lt;/span&gt; &lt;span class="cf2"&gt;Sub&lt;/span&gt; RunWorkerStart(&lt;span class="cf2"&gt;ByVal&lt;/span&gt; sender &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;Object&lt;/span&gt;, &lt;span class="cf2"&gt;ByVal&lt;/span&gt; e &lt;span class="cf2"&gt;As&lt;/span&gt; DoWorkEventArgs)&lt;br /&gt;&lt;span class="cf2"&gt;Dim&lt;/span&gt; T &lt;span class="cf2"&gt;As&lt;/span&gt; clsWork = &lt;span class="cf2"&gt;CType&lt;/span&gt;(e.Argument, clsWork)&lt;br /&gt;e.Result = &lt;span class="cf2"&gt;New&lt;/span&gt; clsResult(T.ID, T.Work.Invoke(T.Param))&lt;br /&gt;&lt;span class="cf2"&gt;End&lt;/span&gt; &lt;span class="cf2"&gt;Sub&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;span class="cf2"&gt;Private&lt;/span&gt; &lt;span class="cf2"&gt;Sub&lt;/span&gt; RunWorkerCompleted(&lt;span class="cf2"&gt;ByVal&lt;/span&gt; sender &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;Object&lt;/span&gt;, &lt;span class="cf2"&gt;ByVal&lt;/span&gt; e &lt;span class="cf2"&gt;As&lt;/span&gt; RunWorkerCompletedEventArgs)&lt;br /&gt;&lt;span class="cf2"&gt;SyncLock&lt;/span&gt; _ThreadLock&lt;br /&gt;&lt;span class="cf2"&gt;Dim&lt;/span&gt; T &lt;span class="cf2"&gt;As&lt;/span&gt; clsResult = &lt;span class="cf2"&gt;CType&lt;/span&gt;(e.Result, clsResult)&lt;br /&gt;&lt;br /&gt;&lt;span class="cf2"&gt;RaiseEvent&lt;/span&gt; WorkComplete(&lt;span class="cf2"&gt;Me&lt;/span&gt;, &lt;span class="cf2"&gt;New&lt;/span&gt; WorkCompleteEventArgs(T.ID, T.Result))&lt;br /&gt;_HadComplete += 1&lt;br /&gt;&lt;span class="cf2"&gt;If&lt;/span&gt; _Work.Count &amp;gt; 0 &lt;span class="cf2"&gt;Then&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;span class="cf2"&gt;Dim&lt;/span&gt; tW &lt;span class="cf2"&gt;As&lt;/span&gt; BackgroundWorker = &lt;span class="cf2"&gt;CType&lt;/span&gt;(sender, BackgroundWorker)&lt;br /&gt;&lt;span class="cf2"&gt;If&lt;/span&gt; tW.IsBusy = &lt;span class="cf2"&gt;False Then&lt;/span&gt; RaiseWorkStart(tW, _Work.Dequeue)&lt;br /&gt;&lt;span class="cf2"&gt;Else&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;span class="cf2"&gt;If&lt;/span&gt; _HadComplete &amp;gt;= _ID &lt;span class="cf2"&gt;Then&lt;/span&gt; &lt;span class="cf2"&gt;RaiseEvent&lt;/span&gt; AllWorkComplete(&lt;span class="cf2"&gt;Me&lt;/span&gt;, &lt;span class="cf2"&gt;New&lt;/span&gt; EventArgs)&lt;br /&gt;&lt;span class="cf2"&gt;End&lt;/span&gt; &lt;span class="cf2"&gt;If&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;span class="cf2"&gt;End&lt;/span&gt; &lt;span class="cf2"&gt;SyncLock&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;span class="cf2"&gt;End&lt;/span&gt; &lt;span class="cf2"&gt;Sub&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;End&lt;/span&gt; &lt;span class="cf2"&gt;Class&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;Public&lt;/span&gt; &lt;span class="cf2"&gt;Class&lt;/span&gt; WorkStartSuspendEventArgs&lt;br /&gt;&lt;span class="cf2"&gt;Inherits&lt;/span&gt; EventArgs&lt;br /&gt;&lt;span class="cf2"&gt;Public&lt;/span&gt; ID &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;Integer&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;span class="cf2"&gt;Public&lt;/span&gt; &lt;span class="cf2"&gt;Sub&lt;/span&gt; &lt;span class="cf2"&gt;New&lt;/span&gt;(&lt;span class="cf2"&gt;ByVal&lt;/span&gt; ID &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;Integer&lt;/span&gt;)&lt;br /&gt;&lt;span class="cf2"&gt;Me&lt;/span&gt;.ID = ID&lt;br /&gt;&lt;span class="cf2"&gt;End&lt;/span&gt; &lt;span class="cf2"&gt;Sub&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;End&lt;/span&gt; &lt;span class="cf2"&gt;Class&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;Public&lt;/span&gt; &lt;span class="cf2"&gt;Class&lt;/span&gt; WorkCompleteEventArgs&lt;br /&gt;&lt;span class="cf2"&gt;Inherits&lt;/span&gt; EventArgs&lt;br /&gt;&lt;span class="cf2"&gt;Public&lt;/span&gt; ID &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;Integer&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;span class="cf2"&gt;Public&lt;/span&gt; Result &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;Object&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;&lt;/span&gt;&lt;span class="cf2"&gt;Public&lt;/span&gt; &lt;span class="cf2"&gt;Sub&lt;/span&gt; &lt;span class="cf2"&gt;New&lt;/span&gt;(&lt;span class="cf2"&gt;ByVal&lt;/span&gt; ID &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;Integer&lt;/span&gt;, &lt;span class="cf2"&gt;ByVal&lt;/span&gt; Result &lt;span class="cf2"&gt;As&lt;/span&gt; &lt;span class="cf2"&gt;Object&lt;/span&gt;)&lt;br /&gt;&lt;span class="cf2"&gt;Me&lt;/span&gt;.ID = ID&lt;br /&gt;&lt;span class="cf2"&gt;Me&lt;/span&gt;.Result = Result&lt;br /&gt;&lt;span class="cf2"&gt;End&lt;/span&gt; &lt;span class="cf2"&gt;Sub&lt;/span&gt;&lt;br /&gt;&lt;span class="cf2"&gt;End&lt;/span&gt; &lt;span class="cf2"&gt;Class&lt;/span&gt;&lt;/div&gt;&lt;img src="http://www.cnblogs.com/grenet/aggbug/2289014.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/grenet/archive/2011/12/21/2289014.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/grenet/archive/2011/06/10/2077228.html</id><title type="text">算法的强大——快速计算一个正二进制整数中包含多少个1</title><summary type="text">原题：一个正整数，转成二进制后，这个二进制数包含多少个1？ 这个问题在网上看过多次，几番思考，也没有什么好的办法。采用最基本的办法，逐位判断，是1的统计加1，最后将统计数返回。 以下是这个思路的VB2008代码，不失一般性，将正整数的范围控制在（1~231-1） Private Function GetCount1OfValue(ByVal Value As Integer) As Integer Dim i As Integer, Count As Integer = 0 For i = 0 To 30 If (Value And 2 ^ i) = 2 ^ i Then Count += .</summary><published>2011-06-10T01:07:00Z</published><updated>2011-06-10T01:07:00Z</updated><author><name>万仓一黍</name><uri>http://www.cnblogs.com/grenet/</uri></author><link rel="alternate" href="http://www.cnblogs.com/grenet/archive/2011/06/10/2077228.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/grenet/archive/2011/06/10/2077228.html"/><content type="html">&lt;p&gt;原题：一个正整数，转成二进制后，这个二进制数包含多少个1？&lt;/p&gt;&lt;p&gt;这个问题在网上看过多次，几番思考，也没有什么好的办法。采用最基本的办法，逐位判断，是1的统计加1，最后将统计数返回。&lt;/p&gt;&lt;p&gt;以下是这个思路的VB2008代码，不失一般性，将正整数的范围控制在（1~2&lt;sup&gt;31&lt;/sup&gt;-1）&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-family: Verdana; color: #0000ff"&gt;Private Function &lt;/span&gt;&lt;span style="font-family: Verdana"&gt;GetCount1OfValue(&lt;/span&gt;&lt;span style="font-family: Verdana; color: #0000ff"&gt;ByVal&lt;/span&gt;&lt;span style="font-family: Verdana"&gt; Value&lt;/span&gt;&lt;span style="font-family: Verdana; color: #0000ff"&gt; As Integer&lt;/span&gt;&lt;span style="font-family: Verdana"&gt;) &lt;/span&gt;&lt;span style="font-family: Verdana; color: #0000ff"&gt;As Integer&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: Verdana; color: #0000ff"&gt;Dim&lt;/span&gt;&lt;span style="font-family: Verdana"&gt; i &lt;/span&gt;&lt;span style="font-family: Verdana; color: #0000ff"&gt;As Integer&lt;/span&gt;&lt;span style="font-family: Verdana"&gt;, Count &lt;/span&gt;&lt;span style="font-family: Verdana; color: #0000ff"&gt;As Integer &lt;/span&gt;&lt;span style="font-family: Verdana"&gt;= 0&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-family: Verdana; color: #0000ff"&gt;For&lt;/span&gt;&lt;span style="font-family: Verdana"&gt; i = 0 &lt;/span&gt;&lt;span style="font-family: Verdana; color: #0000ff"&gt;To&lt;/span&gt;&lt;span style="font-family: Verdana"&gt; 30&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-family: Verdana; color: #0000ff"&gt;If&lt;/span&gt;&lt;span style="font-family: Verdana"&gt; (Value &lt;/span&gt;&lt;span style="font-family: Verdana; color: #0000ff"&gt;And&lt;/span&gt;&lt;span style="font-family: Verdana"&gt; 2 ^ i) = 2 ^ i &lt;/span&gt;&lt;span style="font-family: Verdana; color: #0000ff"&gt;Then&lt;/span&gt;&lt;span style="font-family: Verdana"&gt; Count += 1&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-family: Verdana; color: #0000ff"&gt;Next&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-family: Verdana; color: #0000ff"&gt;Return&lt;/span&gt;&lt;span style="font-family: Verdana"&gt; Count&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-family: Verdana; color: #0000ff"&gt;End Function&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: Verdana"&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: Verdana"&gt;但是近日，在网上发现一个很巧妙的算法，能够快速实现上述的计算功能。代码贴于下方&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-family: Verdana; color: #0000ff"&gt;Private Function&lt;/span&gt;&lt;span style="font-family: Verdana"&gt; GetCount1OfValue(&lt;/span&gt;&lt;span style="font-family: Verdana; color: #0000ff"&gt;ByVal&lt;/span&gt;&lt;span style="font-family: Verdana"&gt; Value&lt;/span&gt;&lt;span style="font-family: Verdana; color: #0000ff"&gt; As Integer&lt;/span&gt;&lt;span style="font-family: Verdana"&gt;) &lt;/span&gt;&lt;span style="font-family: Verdana; color: #0000ff"&gt;As Integer&lt;/span&gt;&lt;span style="font-family: Verdana"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-family: Verdana; color: #0000ff"&gt;Dim&lt;/span&gt;&lt;span style="font-family: Verdana"&gt; Count &lt;/span&gt;&lt;span style="font-family: Verdana; color: #0000ff"&gt;As Integer &lt;/span&gt;&lt;span style="font-family: Verdana"&gt;= 0&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-family: Verdana; color: #0000ff"&gt;Do While&lt;/span&gt;&lt;span style="font-family: Verdana"&gt; Value &amp;gt; 0&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: Verdana"&gt;Value = Value &lt;/span&gt;&lt;span style="font-family: Verdana; color: #0000ff"&gt;And&lt;/span&gt;&lt;span style="font-family: Verdana"&gt; (Value - 1)&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: Verdana"&gt;Count +=1&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-family: Verdana; color: #0000ff"&gt;Loop&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-family: Verdana; color: #0000ff"&gt;Return&lt;/span&gt;&lt;span style="font-family: Verdana"&gt; Count&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-family: Verdana; color: #0000ff"&gt;End Function&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: Verdana"&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: Verdana"&gt;这段代码的精髓就是在这一句：Value = Value And (Value - 1)&lt;br /&gt;&lt;/p&gt;&lt;/span&gt;&lt;p&gt;&lt;span style="font-family: Verdana"&gt;曾经用过类似语句的在我的博客&amp;#8220;&lt;a href="http://www.cnblogs.com/grenet/archive/2011/03/04/1970541.html"&gt;判断是否是2的N次方&amp;#8212;&amp;#8212;证明x &amp;amp; (x - 1)==0的正确性&lt;/a&gt;&amp;#8221;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: Verdana"&gt;那么这句语句到底起到什么作用呢？看下面的分析&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: Verdana"&gt;假设Value=X&lt;sub&gt;1&lt;/sub&gt;X&lt;sub&gt;2&lt;/sub&gt;&amp;#8230;&amp;#8230;X&lt;sub&gt;n-1&lt;/sub&gt;X&lt;sub&gt;n&lt;/sub&gt;，其中X&lt;sub&gt;i&lt;/sub&gt;(1&amp;#8804;i&amp;#8804;n)为1或0&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: Verdana"&gt;不妨设X&lt;sub&gt;i&lt;/sub&gt;是最右边的1，那么Value就可以写成如下的形式&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: Verdana"&gt;Value=X&lt;sub&gt;1&lt;/sub&gt;X&lt;sub&gt;2&lt;/sub&gt;&amp;#8230;&amp;#8230;X&lt;sub&gt;i-1&lt;/sub&gt;X&lt;sub&gt;i&lt;/sub&gt;0&amp;#8230;&amp;#8230;0，其中(1&amp;#8804;i&amp;#8804;n)，X&lt;sub&gt;i&lt;/sub&gt;后面有n-i个0&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: Verdana"&gt;因为X&lt;sub&gt;i&lt;/sub&gt;=1，所以Value=X&lt;sub&gt;1&lt;/sub&gt;X&lt;sub&gt;2&lt;/sub&gt;&amp;#8230;&amp;#8230;X&lt;sub&gt;i-1&lt;/sub&gt;10&amp;#8230;&amp;#8230;0，其中(1&amp;#8804;i&amp;#8804;n)，1后面有n-i个0&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: Verdana"&gt;则Value-1=X&lt;sub&gt;1&lt;/sub&gt;X&lt;sub&gt;2&lt;/sub&gt;&amp;#8230;&amp;#8230;X&lt;sub&gt;i-1&lt;/sub&gt;01&amp;#8230;&amp;#8230;1，其中(1&amp;#8804;i&amp;#8804;n)，0后面有n-i个1&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: Verdana"&gt;则Value And (Value-1)=X&lt;sub&gt;1&lt;/sub&gt;X&lt;sub&gt;2&lt;/sub&gt;&amp;#8230;&amp;#8230;X&lt;sub&gt;i-1&lt;/sub&gt;00&amp;#8230;&amp;#8230;0，其中(1&amp;#8804;i&amp;#8804;n)，X&lt;sub&gt;i-1&lt;/sub&gt;后面有n-i+1个0&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: Verdana"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: Verdana"&gt;因此，Value And (Value-1)的效果把最右边的1变成0&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: Verdana"&gt;在上面的代码中，每把最右边的1变成0，则统计数加1，直到所有的1变成0为止。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: Verdana"&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: Verdana"&gt;这两个算法，第一个算法的循环次数是固定的，是31次，无论数值是多少（必须在范围之内）。而第二个算法和Value中的1的个数有关，循环的次数就是1的个数，可见该算法之妙。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: Verdana"&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: Verdana"&gt;&lt;/span&gt;&lt;span style="font-family: Verdana"&gt;&amp;nbsp;&lt;/p&gt;&lt;/span&gt;&lt;img src="http://www.cnblogs.com/grenet/aggbug/2077228.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/grenet/archive/2011/06/10/2077228.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/grenet/archive/2011/06/09/2075987.html</id><title type="text">Win7和WinXP共享的设置问题二则——共享打印机和FTP</title><summary type="text">时至今日，一个小型的局域网中的操作系统，Win7和WinXP共存的现象已经是很普遍的了（就像当时WinXP和Win98曾经共存了一段时间一样）。那么在Win7和WinXP之间的设置资源共享就得费一番周折了。本人今日碰到二则事例，在网上查了很多资料后，很多都是言语寥寥，不能解决实际问题。在仔细的搜索一番后，找到两个帖子，都顺利的解决了我的问题。在这儿，着文以记之。也是给更多的人一个参考。 一、Win7访问WinXP的共享打印机 在许多的网上的帖子上说，一个是开放GUEST帐号，一个是通过添加网络端口的打印机。这两个，我都试过，前一个，丝毫不起作用，Win7能看到WinXP的机器，但看不到其共享.</summary><published>2011-06-09T04:57:00Z</published><updated>2011-06-09T04:57:00Z</updated><author><name>万仓一黍</name><uri>http://www.cnblogs.com/grenet/</uri></author><link rel="alternate" href="http://www.cnblogs.com/grenet/archive/2011/06/09/2075987.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/grenet/archive/2011/06/09/2075987.html"/><content type="html">&lt;p&gt;时至今日，一个小型的局域网中的操作系统，Win7和WinXP共存的现象已经是很普遍的了（就像当时WinXP和Win98曾经共存了一段时间一样）。那么在Win7和WinXP之间的设置资源共享就得费一番周折了。本人今日碰到二则事例，在网上查了很多资料后，很多都是言语寥寥，不能解决实际问题。在仔细的搜索一番后，找到两个帖子，都顺利的解决了我的问题。在这儿，着文以记之。也是给更多的人一个参考。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;一、Win7访问WinXP的共享打印机&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;/strong&gt;在许多的网上的帖子上说，一个是开放GUEST帐号，一个是通过添加网络端口的打印机。这两个，我都试过，前一个，丝毫不起作用，Win7能看到WinXP的机器，但看不到其共享的打印机。后一个，虽然顺利添加了WinXP的打印机，但是打印的文件却都是空白纸，更新了打印机驱动也没有效果。&lt;/p&gt;&lt;p&gt;解决方案&amp;#8220;&lt;a href="http://apps.hi.baidu.com/share/detail/16063072"&gt;http://apps.hi.baidu.com/share/detail/16063072&lt;/a&gt;&amp;#8221;&lt;/p&gt;&lt;p&gt;现在将解决步骤贴于下方，供大家参考&lt;/p&gt;&lt;p&gt;Win7机器方：&lt;/p&gt;&lt;p&gt;1、开启的服务&lt;br /&gt;右键点击我的电脑或计算机&amp;#8212;管理----服务和应用程序，打开服务&lt;br /&gt;或者用WIN+R打开运行---输入services.msc回车，打开服务设置&lt;/p&gt;&lt;p&gt;开启以下服务：&lt;/p&gt;&lt;p&gt;Server &lt;br /&gt;Workstation&lt;br /&gt;Computer Browser&lt;br /&gt;DHCP Client&lt;br /&gt;Remote Procedure Call&lt;br /&gt;Remote Procedure Call (RPC) Locator&lt;br /&gt;DNS Client&lt;br /&gt;Function Discovery Resource Publication&lt;br /&gt;UPnP Device Host&lt;br /&gt;SSDP Discovery&lt;br /&gt;TIP/IP NetBIOSHelper &lt;/p&gt;&lt;p&gt;2、Win7和WinXP两台机器要在一个工作组里&lt;/p&gt;&lt;p&gt;3、开启网络共享和文件共享&lt;/p&gt;&lt;p&gt;在&amp;#8220;针对不同的网络配置文件更改共享选项&amp;#8221;下勾选&amp;#8220;启用网络发现&amp;#8221;和&amp;#8220;启用文件和打印机共享&amp;#8221;&lt;/p&gt;&lt;p&gt;在&amp;#8220;允许程序通过Windows防火墙通信&amp;#8221;下勾选&amp;#8220;网络发现&amp;#8221;和&amp;#8220;文件和打印机共享&amp;#8221;。并且&amp;#8220;家庭/工作(专用)&amp;#8221;和&amp;#8220;公用&amp;#8221;都勾选&lt;/p&gt;&lt;p&gt;4、Win7中应该启用Guest帐号&lt;/p&gt;&lt;p&gt;WinXP机器方：&lt;/p&gt;&lt;p&gt;1、首先要启用&amp;#8220;文件和打印机共享&amp;#8221;&lt;/p&gt;&lt;p&gt;注意：在&amp;#8220;本地连接 属性&amp;#8221;下&amp;#8220;Microsoft的网络的文件和打印机共享&amp;#8221;下的&amp;#8220;协议&amp;#8221;中的&amp;#8220;network monitor driver协议&amp;#8221;也要安装&lt;/p&gt;&lt;p&gt;2、开始-运行-services.msc- 启动&amp;#8220;server服务&amp;#8221;。&lt;br /&gt;3、组策略设置: &lt;br /&gt;开始菜单运行-secpol.msc -安全设置-本地策略&lt;br /&gt;用户权利指派- &amp;#8220;拒绝从网络访问这台计算机&amp;#8221;属性,删除里面的&amp;#8220;所有用户组&amp;#8221;。重点是删除&amp;#8220;Guest&amp;#8221;帐号。&lt;/p&gt;&lt;p&gt;安全选项： &lt;br /&gt;网络访问：不允许SAM 帐户的匿名枚举，属性给&amp;#8220;停用&amp;#8221;。&lt;br /&gt;网络访问：不允许 SAM 帐户和共享的匿名枚举，属性给&amp;#8220;停用&amp;#8221;。&lt;br /&gt;网络访问：本地帐户的共享和安全模型，属性改为&amp;#8220;经典 - 本地用户以自己的身份验证&amp;#8221;。&lt;br /&gt;4、用户管理---启动guest用户 &lt;br /&gt;5、重启WinXP电脑。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;笔者按照上述的方法做了一遍之后，Win7成功的在网络共享里发现WinXP的共享打印机，双击，按照提示安装打印机驱动，成功的将网络打印机设为默认的打印机。并且可以正常的使用。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;二、Win7的不关闭防火墙下的FTP设置&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;网络上介绍的Win7下的FTP设置，最后都会来一句，如果不能正常访问，把&amp;#8220;Win7的防火墙&amp;#8221;关闭。的确在关闭Win7的防火墙之后，其余的电脑都能正常访问FTP了。而一旦开启了Win7的防火墙，就无法正常的访问FTP了。&lt;/p&gt;&lt;p&gt;问题出在防火墙处。&lt;/p&gt;&lt;p&gt;一般的文章中介绍，在&amp;#8220;允许程序通过Windows防火墙通信&amp;#8221;中勾选&amp;#8220;FTP服务器&amp;#8221;，就能使FTP通过防火墙。但经过实际使用来看，这是不行的。&lt;/p&gt;&lt;p&gt;在&amp;#8220;&lt;a href="http://www.downcc.com/tech/info/672245.html"&gt;http://www.downcc.com/tech/info/672245.html&lt;/a&gt;&amp;#8221;中提到了解决办法。&lt;/p&gt;&lt;p&gt;就是在&amp;#8220;允许程序通过Windows防火墙通信&amp;#8221;中不仅仅要勾选&amp;#8220;FTP服务器&amp;#8221;，还要添加&amp;#8220;inetinfo.exe&amp;#8221;。&lt;/p&gt;&lt;p&gt;首先找到这个文件&lt;/p&gt;&lt;p&gt;通过笔者的本地搜索，在本机上的位置上有两个，分别是&lt;/p&gt;&lt;p&gt;C:\Windows\winsxs\x86_microsoft-windows-iis-metabase_31bf3856ad364e35_6.1.7600.16385_none_39084df88346b717\inetinfo.exe&lt;/p&gt;&lt;p&gt;C:\Windows\winsxs\x86_microsoft-windows-iis-metabase_31bf3856ad364e35_6.1.7601.17514_none_3b3961c080353ab1\inetinfo.exe&lt;/p&gt;&lt;p&gt;在&amp;#8220;允许程序通过Windows防火墙通信&amp;#8221;下点击&amp;#8220;允许运行另一程序&amp;#8221;下点击&amp;#8220;浏览&amp;#8221;，找到上面的两个程序，点&amp;#8220;打开&amp;#8221;即可。&lt;/p&gt;&lt;p&gt;会发现在&amp;#8220;允许的程序和功能&amp;#8221;中已经有了&amp;#8220;Internet Information Services&amp;#8221;并且打上了勾。&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;在如上的操作后，在开启Win7的防火墙之后，其他的机器也能正常的访问FTP了。其实Win7的FTP就是IIS下的一个子功能，所以也必须使IIS通过防火墙。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;上述的两个问题，都是在众多网页中寻觅出来的正解并且经过验证可行的。着文以记之。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/grenet/aggbug/2075987.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/grenet/archive/2011/06/09/2075987.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/grenet/archive/2011/04/29/2032812.html</id><title type="text">再议“生成全排列算法”</title><summary type="text">看了“白话算法(7) 生成全排列的几种思路(一)”和“白话算法(7) 生成全排列的几种思路(二) 康托展开”。在此，将以前本人推导的全排列算法介绍一下，和广大的网友交流一下。 以例子说明，用0、1、2、3，四个数组成全排列。 首先可以知道，这四个数组成的全排列一共有4！=24个。那么给这24个全排列编号，分别为0、1、2……23。再给定一个算法，通过编号计算出一个全排列。本文的目的就是找到这样的算法。 把所有的全排列列举出来可以发现，0在末位的有6个，1在末位的有6个，等等。 观察0在末位的六个，分别是 1、2、3、0 1、3、2、0 2、1、3、0 2、3、1、0 3、1、2、0 3、2、.</summary><published>2011-04-29T07:39:00Z</published><updated>2011-04-29T07:39:00Z</updated><author><name>万仓一黍</name><uri>http://www.cnblogs.com/grenet/</uri></author><link rel="alternate" href="http://www.cnblogs.com/grenet/archive/2011/04/29/2032812.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/grenet/archive/2011/04/29/2032812.html"/><content type="html">&lt;p&gt;看了&amp;#8220;&lt;a href="http://www.cnblogs.com/1-2-3/archive/2011/04/17/generate-permutation-part1.html"&gt;白话算法(7) 生成全排列的几种思路(一)&lt;/a&gt;&amp;#8221;和&amp;#8220;&lt;a href="http://www.cnblogs.com/1-2-3/archive/2011/04/25/generate-permutation-part2.html"&gt;白话算法(7) 生成全排列的几种思路(二) 康托展开&lt;/a&gt;&amp;#8221;。在此，将以前本人推导的全排列算法介绍一下，和广大的网友交流一下。&lt;/p&gt;&lt;p&gt;以例子说明，用0、1、2、3，四个数组成全排列。&lt;/p&gt;&lt;p&gt;首先可以知道，这四个数组成的全排列一共有4！=24个。那么给这24个全排列编号，分别为0、1、2&amp;#8230;&amp;#8230;23。再给定一个算法，通过编号计算出一个全排列。本文的目的就是找到这样的算法。&lt;/p&gt;&lt;p&gt;把所有的全排列列举出来可以发现，0在末位的有6个，1在末位的有6个，等等。&lt;/p&gt;&lt;p&gt;观察0在末位的六个，分别是&lt;/p&gt;&lt;p&gt;1、2、3、0&lt;/p&gt;&lt;p&gt;1、3、2、0&lt;/p&gt;&lt;p&gt;2、1、3、0&lt;/p&gt;&lt;p&gt;2、3、1、0&lt;/p&gt;&lt;p&gt;3、1、2、0&lt;/p&gt;&lt;p&gt;3、2、1、0&lt;/p&gt;&lt;p&gt;可以看出这6个全排列，除了末位是0外，前面三个数正好是1、2、3的全排列&lt;/p&gt;&lt;p&gt;再观察1在末位的六个，分别是&lt;/p&gt;&lt;p&gt;0、2、3、1&lt;/p&gt;&lt;p&gt;0、3、2、1&lt;/p&gt;&lt;p&gt;2、0、3、1&lt;/p&gt;&lt;p&gt;2、3、0、1&lt;/p&gt;&lt;p&gt;3、0、2、1&lt;/p&gt;&lt;p&gt;3、2、0、1&lt;/p&gt;&lt;p&gt;也可以看出这6个全排列，除了末位是1外，前面三个数正好是0、2、3的全排列&lt;/p&gt;&lt;p&gt;类似的，末位是2和3的6个全排列，除了末位是一样的以外，前面三个数正好是剩下的三个数的全排列。&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;于是该问题就可以用下面的步骤来解决。&lt;/p&gt;&lt;p&gt;1、根据编号确定末位数字&lt;/p&gt;&lt;p&gt;2、确定末位数字后，获得剩余的数字&lt;/p&gt;&lt;p&gt;3、对编号适当的处理，得到新的编号&lt;/p&gt;&lt;p&gt;4、问题演化成除了末位数字后，用新的编号和剩余的数字，计算剩余数字的全排列。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;再用一个具体的例子来说明。比方说，用编号13来计算0、1、2、3的一个全排列。&lt;/p&gt;&lt;p&gt;1、先给这4个数字排好序。是0、1、2、3&lt;/p&gt;&lt;p&gt;2、计算[13/3!]+1=3，表示末位数是第3个数。注：[X]表示取X的整数部分。&lt;/p&gt;&lt;p&gt;3、把第3个数和第4个数（未排的最后1个数）交换。此时，数字的顺序是0、1、3、&lt;span style="color: #0000ff"&gt;2&lt;/span&gt;。蓝色的表示已经排好。&lt;/p&gt;&lt;p&gt;4、新的编号为13 mod 3!=1&lt;/p&gt;&lt;p&gt;5、计算[1/2!]+1=1，表示末位数是第1个数。&lt;/p&gt;&lt;p&gt;6、把第1个数和第3个数（未排的最后1个数）交换。此时，数字的顺序是3、1、&lt;span style="color: #0000ff"&gt;0、2&lt;/span&gt;。蓝色的表示已经排好。&lt;/p&gt;&lt;p&gt;7、新的编号为1&amp;nbsp;mod 2!=1&lt;/p&gt;&lt;p&gt;8、计算[1/1!]+1=2，表示末位数是第2个数。&lt;/p&gt;&lt;p&gt;9、把第2个数和第2个数（未排的最后1个数）交换。此时，数字的顺序是3、&lt;span style="color: #0000ff"&gt;1、&lt;/span&gt;&lt;span style="color: #0000ff"&gt;0、2&lt;/span&gt;。蓝色的表示已经排好。&lt;/p&gt;&lt;p&gt;10、因为只剩下一个数，所以编号13对应的全排列就是3、1、0、2&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;其他的编号计算方法和此一样。&lt;/p&gt;&lt;p&gt;后面的这个表格就是按照上面的算法得到所有的编号和全排列的关系&lt;/p&gt;&lt;table bordercolor="#000000" cellspacing="0" cellpadding="0" align="center" border="1"&gt;&lt;tbody&gt;&lt;tr height="19"&gt;&lt;td align="center" height="19"&gt;A(0)&lt;/td&gt;&lt;td align="center"&gt;A(1)&lt;/td&gt;&lt;td align="center"&gt;A(2)&lt;/td&gt;&lt;td align="center"&gt;A(3)&lt;/td&gt;&lt;td align="center"&gt;编号&lt;/td&gt;&lt;/tr&gt;&lt;tr height="19"&gt;&lt;td align="center" width="72" height="19"&gt;1&lt;/td&gt;&lt;td align="center" width="72"&gt;2&lt;/td&gt;&lt;td align="center" width="72"&gt;3&lt;/td&gt;&lt;td align="center" width="72"&gt;0&lt;/td&gt;&lt;td align="center" width="72"&gt;0&lt;/td&gt;&lt;/tr&gt;&lt;tr height="19"&gt;&lt;td align="center" height="19"&gt;2&lt;/td&gt;&lt;td align="center"&gt;1&lt;/td&gt;&lt;td align="center"&gt;3&lt;/td&gt;&lt;td align="center"&gt;0&lt;/td&gt;&lt;td align="center"&gt;1&lt;/td&gt;&lt;/tr&gt;&lt;tr height="19"&gt;&lt;td align="center" height="19"&gt;2&lt;/td&gt;&lt;td align="center"&gt;3&lt;/td&gt;&lt;td align="center"&gt;1&lt;/td&gt;&lt;td align="center"&gt;0&lt;/td&gt;&lt;td align="center"&gt;2&lt;/td&gt;&lt;/tr&gt;&lt;tr height="19"&gt;&lt;td align="center" height="19"&gt;3&lt;/td&gt;&lt;td align="center"&gt;2&lt;/td&gt;&lt;td align="center"&gt;1&lt;/td&gt;&lt;td align="center"&gt;0&lt;/td&gt;&lt;td align="center"&gt;3&lt;/td&gt;&lt;/tr&gt;&lt;tr height="19"&gt;&lt;td align="center" height="19"&gt;1&lt;/td&gt;&lt;td align="center"&gt;3&lt;/td&gt;&lt;td align="center"&gt;2&lt;/td&gt;&lt;td align="center"&gt;0&lt;/td&gt;&lt;td align="center"&gt;4&lt;/td&gt;&lt;/tr&gt;&lt;tr height="19"&gt;&lt;td align="center" height="19"&gt;3&lt;/td&gt;&lt;td align="center"&gt;1&lt;/td&gt;&lt;td align="center"&gt;2&lt;/td&gt;&lt;td align="center"&gt;0&lt;/td&gt;&lt;td align="center"&gt;5&lt;/td&gt;&lt;/tr&gt;&lt;tr height="19"&gt;&lt;td align="center" height="19"&gt;3&lt;/td&gt;&lt;td align="center"&gt;2&lt;/td&gt;&lt;td align="center"&gt;0&lt;/td&gt;&lt;td align="center"&gt;1&lt;/td&gt;&lt;td align="center"&gt;6&lt;/td&gt;&lt;/tr&gt;&lt;tr height="19"&gt;&lt;td align="center" height="19"&gt;2&lt;/td&gt;&lt;td align="center"&gt;3&lt;/td&gt;&lt;td align="center"&gt;0&lt;/td&gt;&lt;td align="center"&gt;1&lt;/td&gt;&lt;td align="center"&gt;7&lt;/td&gt;&lt;/tr&gt;&lt;tr height="19"&gt;&lt;td align="center" height="19"&gt;2&lt;/td&gt;&lt;td align="center"&gt;0&lt;/td&gt;&lt;td align="center"&gt;3&lt;/td&gt;&lt;td align="center"&gt;1&lt;/td&gt;&lt;td align="center"&gt;8&lt;/td&gt;&lt;/tr&gt;&lt;tr height="19"&gt;&lt;td align="center" height="19"&gt;0&lt;/td&gt;&lt;td align="center"&gt;2&lt;/td&gt;&lt;td align="center"&gt;3&lt;/td&gt;&lt;td align="center"&gt;1&lt;/td&gt;&lt;td align="center"&gt;9&lt;/td&gt;&lt;/tr&gt;&lt;tr height="19"&gt;&lt;td align="center" height="19"&gt;3&lt;/td&gt;&lt;td align="center"&gt;0&lt;/td&gt;&lt;td align="center"&gt;2&lt;/td&gt;&lt;td align="center"&gt;1&lt;/td&gt;&lt;td align="center"&gt;10&lt;/td&gt;&lt;/tr&gt;&lt;tr height="19"&gt;&lt;td align="center" height="19"&gt;0&lt;/td&gt;&lt;td align="center"&gt;3&lt;/td&gt;&lt;td align="center"&gt;2&lt;/td&gt;&lt;td align="center"&gt;1&lt;/td&gt;&lt;td align="center"&gt;11&lt;/td&gt;&lt;/tr&gt;&lt;tr height="19"&gt;&lt;td align="center" height="19"&gt;1&lt;/td&gt;&lt;td align="center"&gt;3&lt;/td&gt;&lt;td align="center"&gt;0&lt;/td&gt;&lt;td align="center"&gt;2&lt;/td&gt;&lt;td align="center"&gt;12&lt;/td&gt;&lt;/tr&gt;&lt;tr height="19"&gt;&lt;td align="center" height="19"&gt;3&lt;/td&gt;&lt;td align="center"&gt;1&lt;/td&gt;&lt;td align="center"&gt;0&lt;/td&gt;&lt;td align="center"&gt;2&lt;/td&gt;&lt;td align="center"&gt;13&lt;/td&gt;&lt;/tr&gt;&lt;tr height="19"&gt;&lt;td align="center" height="19"&gt;3&lt;/td&gt;&lt;td align="center"&gt;0&lt;/td&gt;&lt;td align="center"&gt;1&lt;/td&gt;&lt;td align="center"&gt;2&lt;/td&gt;&lt;td align="center"&gt;14&lt;/td&gt;&lt;/tr&gt;&lt;tr height="19"&gt;&lt;td align="center" height="19"&gt;0&lt;/td&gt;&lt;td align="center"&gt;3&lt;/td&gt;&lt;td align="center"&gt;1&lt;/td&gt;&lt;td align="center"&gt;2&lt;/td&gt;&lt;td align="center"&gt;15&lt;/td&gt;&lt;/tr&gt;&lt;tr height="19"&gt;&lt;td align="center" height="19"&gt;1&lt;/td&gt;&lt;td align="center"&gt;0&lt;/td&gt;&lt;td align="center"&gt;3&lt;/td&gt;&lt;td align="center"&gt;2&lt;/td&gt;&lt;td align="center"&gt;16&lt;/td&gt;&lt;/tr&gt;&lt;tr height="19"&gt;&lt;td align="center" height="19"&gt;0&lt;/td&gt;&lt;td align="center"&gt;1&lt;/td&gt;&lt;td align="center"&gt;3&lt;/td&gt;&lt;td align="center"&gt;2&lt;/td&gt;&lt;td align="center"&gt;17&lt;/td&gt;&lt;/tr&gt;&lt;tr height="19"&gt;&lt;td align="center" height="19"&gt;1&lt;/td&gt;&lt;td align="center"&gt;2&lt;/td&gt;&lt;td align="center"&gt;0&lt;/td&gt;&lt;td align="center"&gt;3&lt;/td&gt;&lt;td align="center"&gt;18&lt;/td&gt;&lt;/tr&gt;&lt;tr height="19"&gt;&lt;td align="center" height="19"&gt;2&lt;/td&gt;&lt;td align="center"&gt;1&lt;/td&gt;&lt;td align="center"&gt;0&lt;/td&gt;&lt;td align="center"&gt;3&lt;/td&gt;&lt;td align="center"&gt;19&lt;/td&gt;&lt;/tr&gt;&lt;tr height="19"&gt;&lt;td align="center" height="19"&gt;2&lt;/td&gt;&lt;td align="center"&gt;0&lt;/td&gt;&lt;td align="center"&gt;1&lt;/td&gt;&lt;td align="center"&gt;3&lt;/td&gt;&lt;td align="center"&gt;20&lt;/td&gt;&lt;/tr&gt;&lt;tr height="19"&gt;&lt;td align="center" height="19"&gt;0&lt;/td&gt;&lt;td align="center"&gt;2&lt;/td&gt;&lt;td align="center"&gt;1&lt;/td&gt;&lt;td align="center"&gt;3&lt;/td&gt;&lt;td align="center"&gt;21&lt;/td&gt;&lt;/tr&gt;&lt;tr height="19"&gt;&lt;td align="center" height="19"&gt;1&lt;/td&gt;&lt;td align="center"&gt;0&lt;/td&gt;&lt;td align="center"&gt;2&lt;/td&gt;&lt;td align="center"&gt;3&lt;/td&gt;&lt;td align="center"&gt;22&lt;/td&gt;&lt;/tr&gt;&lt;tr height="19"&gt;&lt;td align="center" height="19"&gt;0&lt;/td&gt;&lt;td align="center"&gt;1&lt;/td&gt;&lt;td align="center"&gt;2&lt;/td&gt;&lt;td align="center"&gt;3&lt;/td&gt;&lt;td align="center"&gt;23&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;通过这样的算法，通过指定的编号就能算出一个全排列。&lt;/p&gt;&lt;p&gt;如果要遍历所有的全排列，则只要遍历编号就能完成。&lt;/p&gt;&lt;p&gt;如果要随机获得一个全排列，则随机生成一个编号，再计算出全排列就可以了。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;具体的代码在我之前的文章&amp;#8220;&lt;a href="http://www.cnblogs.com/grenet/archive/2009/12/12/1622442.html"&gt;遍历排列的实现&amp;#8212;&amp;#8212;VB2005&lt;/a&gt;&amp;#8221;中，这里就不重复贴出了。&lt;/p&gt;&lt;img src="http://www.cnblogs.com/grenet/aggbug/2032812.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/grenet/archive/2011/04/29/2032812.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/grenet/archive/2011/04/21/2023336.html</id><title type="text">质疑贴——对《新版微软一站式示例代码库》中的一个示例的质疑</title><summary type="text">在“新版微软一站式示例代码库发布 - 绑定第三版示例代码浏览器”中，有若干最新的asp.net的示例。 对其中的一个示例的源代码研究了一番。觉得有问题，故在此阐述本人的疑问，望广大网友赐教。 先把这个示例的说明贴在下方。 CSASPNETReverseAJAX, VBASPNETReverseAJAX Downloads CSASPNETReverseAJAX: http://code.msdn.microsoft.com/CSASPNETReverseAJAX-7a1f0c2b VBASPNETReverseAJAX: http://code.msdn.microsoft.com/VBAS.</summary><published>2011-04-21T03:21:00Z</published><updated>2011-04-21T03:21:00Z</updated><author><name>万仓一黍</name><uri>http://www.cnblogs.com/grenet/</uri></author><link rel="alternate" href="http://www.cnblogs.com/grenet/archive/2011/04/21/2023336.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/grenet/archive/2011/04/21/2023336.html"/><content type="html">&lt;p&gt;在&amp;#8220;&lt;a href="http://www.cnblogs.com/Jialiang/archive/2011/04/19/2021294.html"&gt;新版微软一站式示例代码库发布 - 绑定第三版示例代码浏览器&lt;/a&gt;&amp;#8221;中，有若干最新的asp.net的示例。&lt;/p&gt;&lt;p&gt;对其中的一个示例的源代码研究了一番。觉得有问题，故在此阐述本人的疑问，望广大网友赐教。&lt;/p&gt;&lt;p&gt;先把这个示例的说明贴在下方。&lt;/p&gt;&lt;p&gt;CSASPNETReverseAJAX, VBASPNETReverseAJAX&lt;/p&gt;&lt;p&gt;Downloads &lt;br /&gt;CSASPNETReverseAJAX: &lt;a href="http://code.msdn.microsoft.com/CSASPNETReverseAJAX-7a1f0c2b"&gt;http://code.msdn.microsoft.com/CSASPNETReverseAJAX-7a1f0c2b&lt;/a&gt; &lt;br /&gt;VBASPNETReverseAJAX: &lt;a href="http://code.msdn.microsoft.com/VBASPNETReverseAJAX-321a68b0"&gt;http://code.msdn.microsoft.com/VBASPNETReverseAJAX-321a68b0&lt;/a&gt;&lt;/p&gt;&lt;p&gt;反向Ajax又叫Comet模式Ajax, 推模式Ajax, 双向Web和 服务器推模式. 这种技术维护着一个HTTP请求来允许服务器向浏览器推送数据, 而不需要每隔一段特定的时间不断地向服务器提交请求. 这个示例演示了如何在ASP.NET Ajax里使用这种技术。&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;按照上文的文字的理解。应该是浏览器这一端是被动方。而服务器这一端是主动方。服务器在获得消息的更新后，主动通知客户端更新消息的内容。如果是这样就太好了。可是看了源代码后，却发现貌似不是那么一回事。要么就是自己的理解上有问题。&lt;/p&gt;&lt;p&gt;先看看各个文件的作用&lt;/p&gt;&lt;p&gt;Sender.aspx客户端发送消息的页面&lt;/p&gt;&lt;p&gt;Receiver.aspx　 客户端获得消息的页面&lt;/p&gt;&lt;p&gt;Message.vb、ClientAdapter.vb、Client.vb服务器端处理消息的类（采用单实例模式，有点像静态类）&lt;/p&gt;&lt;p&gt;Dispatcher.asmx.vb 服务器端返回消息的WebService&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;那么看看各个文件的关键部分的代码&lt;/p&gt;&lt;p&gt;先看看Sender.aspx，客户端发送消息的页面&lt;/p&gt;&lt;p&gt;&lt;span style="color: #0000ff"&gt;Protected Sub &lt;/span&gt;btnSend_Click(&lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; sender &lt;span style="color: #0000ff"&gt;As Object&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; e &lt;span style="color: #0000ff"&gt;As EventArgs&lt;/span&gt;)&amp;nbsp;&lt;br /&gt;&lt;span style="color: #008000"&gt;' Create a message entity to contain all necessary data.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;Dim&lt;/span&gt; message &lt;span style="color: #0000ff"&gt;As New &lt;/span&gt;Message()&amp;nbsp;&lt;br /&gt;message.RecipientName = tbRecipientName.Text.Trim()&amp;nbsp;&lt;br /&gt;message.MessageContent = tbMessageContent.Text.Trim()&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;If Not String&lt;/span&gt;.IsNullOrWhiteSpace(message.RecipientName) &lt;span style="color: #0000ff"&gt;AndAlso Not String&lt;/span&gt;.IsNullOrEmpty(message.MessageContent) &lt;span style="color: #0000ff"&gt;Then&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008000"&gt;' Call the client adapter to send the message to the particular recipient instantly.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;ClientAdapter.Instance.SendMessage(message)&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span style="color: #008000"&gt;' Display a timestamp.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;lbNotification.Text += DateTime.Now.ToLongTimeString() &amp;amp; "&lt;span style="color: #993300"&gt;: Message sent!&amp;lt;br/&amp;gt;&lt;/span&gt;"&amp;nbsp;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;End If&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;End Sub &lt;/span&gt;&lt;/p&gt;&lt;p&gt;这个函数就是当&amp;#8220;发送消息&amp;#8221;按钮按下时，将客户端的消息写到后台的静态类中。&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;Message.vb、ClientAdapter.vb、Client.vb这三个文件是后台的消息处理静态类，和本文的质疑无关。就不详细说了。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;再看看Dispatcher.asmx.vb，服务器端返回消息的WebService。它将合适的消息返回给调用者。&lt;/p&gt;&lt;p&gt;&amp;lt;WebMethod()&amp;gt;&lt;span style="color: #0000ff"&gt;Public Function&lt;/span&gt; WaitMessage(&lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; userName &lt;span style="color: #0000ff"&gt;As String&lt;/span&gt;) &lt;span style="color: #0000ff"&gt;As String&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;Return&lt;/span&gt; ClientAdapter.Instance.GetMessage(userName)&amp;nbsp;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;End Function &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;最后看看Receiver.aspx，客户端获得消息的页面。它是如何获得后台即时消息的。&lt;/p&gt;&lt;p&gt;&lt;span style="color: #0000ff"&gt;Protected Sub &lt;/span&gt;Page_PreRender(&lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; sender &lt;span style="color: #0000ff"&gt;As Object&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;ByVal&lt;/span&gt; e &lt;span style="color: #0000ff"&gt;As&lt;/span&gt; EventArgs)&amp;nbsp;&lt;br /&gt;&lt;span style="color: #008000"&gt;' Activate the JavaScript waiting loop.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;If &lt;/span&gt;Session(&lt;span style="color: #993300"&gt;"userName"&lt;/span&gt;) &lt;span style="color: #0000ff"&gt;IsNot Nothing &lt;/span&gt;&lt;span style="color: #0000ff"&gt;Then&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;Dim&lt;/span&gt; userName&lt;span style="color: #0000ff"&gt; As String &lt;/span&gt;=&lt;span style="color: #0000ff"&gt; DirectCast&lt;/span&gt;(Session(&lt;span style="color: #993300"&gt;"userName"&lt;/span&gt;), &lt;span style="color: #0000ff"&gt;String&lt;/span&gt;)&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span style="color: #008000"&gt;' Call JavaScript method waitEvent to start the wait loop.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;ClientScript.RegisterStartupScript(&lt;span style="color: #0000ff"&gt;Me&lt;/span&gt;.[&lt;span style="color: #0000ff"&gt;GetType&lt;/span&gt;](), &lt;span style="color: #993300"&gt;"ActivateWaitingLoop"&lt;/span&gt;, &lt;span style="color: #993300"&gt;"waitEvent();"&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;True&lt;/span&gt;)&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;lbNotification.Text = &lt;span style="color: #0000ff"&gt;String&lt;/span&gt;.Format(&lt;span style="color: #993300"&gt;"Your user name is &amp;lt;b&amp;gt;{0}&amp;lt;/b&amp;gt;. It is waiting for new message now."&lt;/span&gt;, userName)&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span style="color: #008000"&gt;' Disable the login.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;tbUserName.Visible = &lt;span style="color: #0000ff"&gt;False&amp;nbsp;&lt;/span&gt;&lt;br /&gt;btnLogin.Visible = &lt;span style="color: #0000ff"&gt;False&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;End If&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;End Sub &lt;/span&gt;&lt;/p&gt;&lt;p&gt;从这一段代码可以看出，在页面完成时，注册了一个JS代码，这个代码是waitEvent();&lt;/p&gt;&lt;p&gt;我们看看这个页面的waitEvent()的代码，看看做了一些什么事。&lt;/p&gt;&lt;p&gt;&amp;lt;script type="text/javascript"&amp;gt;&amp;nbsp;&lt;br /&gt;// This method will persist a http request and wait for messages.&amp;nbsp;&lt;br /&gt;function waitEvent() {&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;VBASPNETReverseAJAX.Dispatcher.WaitMessage("&amp;lt;%= Session("userName") %&amp;gt;",&amp;nbsp;&amp;nbsp;&lt;br /&gt;function (result) {&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;displayMessage(result);&amp;nbsp;&lt;br /&gt; // Keep looping.&amp;nbsp;&lt;br /&gt;setTimeout(waitEvent, 0);&amp;nbsp;&lt;br /&gt;}, &lt;/p&gt;&lt;p&gt;function () {&amp;nbsp;&lt;br /&gt;&amp;nbsp;// Keep looping.&amp;nbsp;&lt;br /&gt;setTimeout(waitEvent, 0);&amp;nbsp;&lt;br /&gt;});&amp;nbsp;&lt;br /&gt;}&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;// Append a message content to the result panel.&amp;nbsp;&lt;br /&gt;function displayMessage(message) {&amp;nbsp;&lt;br /&gt;var panel = document.getElementById("&amp;lt;%= lbMessages.ClientID %&amp;gt;");&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;panel.innerHTML += currentTime() + ": " + message + "&amp;lt;br /&amp;gt;";&amp;nbsp;&lt;br /&gt;}&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;// Return a current time string.&amp;nbsp;&lt;br /&gt;function currentTime() {&amp;nbsp;&lt;br /&gt;var currentDate = new Date()&amp;nbsp;&lt;br /&gt;return currentDate.getHours() + ":" + currentDate.getMinutes() + ":" + currentDate.getSeconds();&amp;nbsp;&lt;br /&gt;}&amp;nbsp;&lt;br /&gt;&amp;lt;/script&amp;gt; &lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;这一段的JS代码，是调用后台的WebService，将后台的消息显示到页面上。&lt;/p&gt;&lt;p&gt;可是，为了达到&amp;#8220;实时&amp;#8221;的效果。它用了下面的一句话&lt;/p&gt;&lt;p&gt;setTimeout(waitEvent, 0);&amp;nbsp;&lt;/p&gt;&lt;p&gt;第二个参数是0，也就意味着是立即调用。&lt;/p&gt;&lt;p&gt;通观整个waitEvent代码，实际上就是一个不停的调用后台的WebService，来获得消息。这似乎还是客户端是主动端，而且由于是一刻不停的调用后台的WebService，岂不是比间隔一段时间调用后台的WebService更加耗费资源吗？如果客户端只有一个还好，若是有成百上千的这样的客户端，那服务器岂不是负担很重？&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;这是我看了源代码后的质疑。也许是哪儿我理解错了。望网友指正赐教。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/grenet/aggbug/2023336.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/grenet/archive/2011/04/21/2023336.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry></feed>
