新材料可让太阳能集热器温度升至220摄氏度

2019-08-04 02:19

“正在进行前期的各项准备工作,手续完善后将立即进场施工”

2、附近没有建筑物时应用双手护住头部和脖子,就地趴进水沟、洼地;

走进小镇,你会惊奇地发现,每一栋居民楼上都有太阳能电池板,而市政大楼上就有74块!

图为袁江接受翁源学子们回赠的爱心花环

在分选过程中,机器人会对物体进行扫描,并通过传感器测量物体尺寸。使用其机械手臂上的两根柔软手指挤压物体以完成抓取,而手指上的压力传感器能够测量抓住物体所需要的力,并以此确定材料刚度。最后,将扫描结果与压力传感器获得的数据相互对比匹配,分辨出物体材质后,Rocycle会将其投入正确的垃圾箱。

手是人类智慧的工具。表现在儿童身上,甚至可以这样说:儿童是用手来思考的,手的自由的使用,不仅表达了儿童的思维,也表达了儿童思考的过程,禁止了儿童手的活动,就相当于禁止了儿童的思考。

“一家成功的企业不仅要在市场上占领高地,更应该在社会责任、社会担当上有所建树,不仅要立志于改善各地的自然环境,还要致力于公益慈善事业,穷则独善其身,富则回报社会,达则兼济天下。”袁江讲道。

“长医附一队”调研组组员在黄金一区的街边热心的为在街边劳作的环卫工人叔叔普及预防流行性疾病小知识,他们在清理垃圾时候更容易接触到一些具有传染性的物质,了解这些知识能够更好帮助到他们了解基础的流行性传染病,能提前做好预防。通讯员陶雨霜摄

为什么会产生龙卷风呢?

据悉,讨火车小学全校师生共计200多人,一直以来,师生健康饮水问题未能得到解决。至此,由广东东日环保股份有限公司爱心捐赠全套饮用水设备及基础设施,彻底解决了该校全体师生饮水健康事宜。

袁江践行着一个优秀企业家 “蓝天白云、青山绿水” 的社会责任和担当,赢得社会各界一致好评,也荣获2016年年度广东绿色企业家称号。

敬请关注华淳传媒新媒体,欢迎留言。

Pam和朋友们设计了观光线路,给初来乍到的小伙伴提供方便的同时,也保护了菜地,避免被人不经意破坏。新闻

昨日道路沿线抛洒物已被苫盖

WE ARE MORE FUN THINK

几个月后,儿童的手不再是一把抓了,而是喜欢两指抓,抓细小的物体:毛线头、小纸屑、床上的一个小碎物。

那么,出现烦躁或者是郁闷的状态时,自己就会想办法调节自己,让自己高兴和开心的。因为,自媒领域是选择自己喜欢的或者是自己爱好的。

习总书记勉励广大青年充分展现自己的抱负和激情,胸怀理想、锤炼品格,脚踏实地、艰苦奋斗,不断书写奉献青春的时代篇。越是艰苦的地方就越能磨练人的意志。“选择我爱的,爱我选择的,即使在三下乡中遇到困难挫折时,我也愿意去付出,去努力”,这大概是每位支医队员的心声。为居民送健康,送温暖,培养大学生扎根基层,服务人民,无私奉献的意识,用自己所学的知识运用到实践中,在实践中成长,成才。

改变世界,无法一朝一夕,但绝对是一点一滴。只要怀抱着让这个世界更美好的心,再渺小的人,也能有撬动地球的能量。

屈迎波

致自己

《致自己》
再难,也要坚持。
再好,也要淡泊。
再差,也要自信。
再多,也要节省。
再冷,也要热情。
记住
昨天,封存。
今天,留着。
明天,争取。
对的,坚持。
错的,放弃。
你再优秀也会有人对你不屑一顾,
你再不堪也会有人把你视若生命。
所以,
得意时不要得瑟,
落魄时不要堕落,
就算你瘦了,
变好看了,
你什么都好了,
不爱你的人还是不爱你。

即使你再胖,
再难看,
再怎么不好,
爱你的人永远不会嫌弃你。
谁若用真心对我,
我便拿命去珍惜,
这句话永远不会过期。
我只会对值得我付出的人付出,
不管是友情还是爱情。
我有我风格,
我有我要求,
我就是我,
不容复制,
亦无可代替。
再差,
世上也只有唯一的一个我。
生活中,我们常常不能明心见性,
是因为我们也放不下,
我们的观念,我们的习惯。
爱出者爱返,福往者福来。
为别人着想,一定就有人想着你,
这就是因果,这就是最朴实的真理!

无助的时候读读这10封信

《第一封》 写给你

假如人生不曾相遇,我还是那个我,偶尔做做梦,然后,开始日复一日的奔波,淹没在这喧嚣的城市里。我不会了解,这个世界还有这样的一个你,让人回味,令我心醉。假如人生不曾相遇,我不会相信,有一种人一认识就觉得温馨,有一种人可以百看不厌。
《第二封》 写给幸福

一直以为幸福在远方,在可以追逐的未来。后来才发现,那些拥抱过的人,握过的手、唱过的歌、流过的泪、爱过的人、所谓的曾经,就是幸福。在无数的夜里,说过的话、打过的电话,看过的电影、流过的眼泪……看见的或看不见的感动,我们都曾经有过,然后在时间的穿梭中,一切成为了永恒!
《第三封》 写给努力

不要抱怨你没有一个好爸爸,不要抱怨你的工作差,不要抱怨怀才不遇无人赏识。现实有太多的不如意,就算生活给你的是垃圾,你同样能把垃圾踩在脚底下登上世界之巅。这个世界只在乎你是否在到达了一定的高度,而不在乎你是踩在巨人的肩膀上上去的,还是踩在垃圾上上去的。
《第四封》 写给修为

看别人不顺眼,是自己修养不够。人愤怒的那一瞬间,智商是零,过一分钟后恢复正常。人的优雅关键在于控制自己的情绪,用嘴伤害人,是最愚蠢的一种行为。
《第五封》 写给了解

有个懂你的人,是最大的幸福。这个人,不一定十全十美,但他能读懂你,能走进你的心灵深处,能看懂你心里的一切。最懂你的人,总是会一直的在你身边,默默守护你,不让你受一点点的委屈。真正爱你的人不会说许多爱你的话,却会做许多爱你的事。
《第六封》 写给独自

一个人单身久了,就不想去恋爱,会感觉朋友越来越重要;一个人单身久了,就不想去逛街,会越来越喜欢在家听歌;一个人单身久了,就变得成熟起来,会比以前越来越爱父母;一个人单身久了,就买很多鞋子,会独自去很多很远的地方旅游;一个人单身久了,就不经意悄悄流泪,但会在众人面前什么都无所谓。
《第七封》 写给宿命

每一段记忆,都有一个密码。只要时间,地点,人物组合正确,无论尘封多久,那人那景都将在遗忘中重新拾起。你也许会说“不是都过去了吗?” 其实过去的只是时间,你依然逃不出,想起了就微笑或悲伤的宿命,那种宿命本叫“无能为力” 。
《第八封》 写给成长

有时候,莫名的心情不好,不想和任何人说话,只想一个人静静的发呆。有时候,想一个人躲起来脆弱,不愿别人看到自己的伤口。有时候,走过熟悉的街角,看到熟悉的背影,突然想起一个人的脸。有时候,别人误解了自己有口无心的话,心里郁闷的发慌。有时候,发现自己一夜之间就长大了。
《第九封》 写给来生

如果有来生,要做一棵树,站成永恒,没有悲欢的姿势。一半在土里安详,一半在风里飞扬,一半洒落阴凉,一半沐浴阳光,非常沉默非常骄傲,不依靠不寻找。
《第十封》 写给本真

身边总有些人,你看见她整天都开心,率真得像个小孩,人人都羡慕她;其实,你哪里知道:前一秒人后还伤心地流着泪的她,后一秒人前即刻洋溢灿烂。他们就像向日葵,向着太阳的正面永远明媚鲜亮,在照不到的背面却将悲伤深藏。

,请好好善待自己,一辈子不长!

无助的时候读读这10封信。

(转)软件工程师所需掌握的“终极技术”是什么?

(转)软件工程师所需掌握的“终极技术”是什么

转载原始出处  http://yunli.blog.51cto.com/831344/1019990

最近,我在微博上看到@程序员邹欣老师发的一条微博 — “不少大学同学都有一个想法:先做几年技术,然后做管理;也有一些同学说:我技术不行,希望直接找到一个管理的工作,就像PM那样。请看 PM 需要什么样的能力:(链接略去)”。在读这条微博的前一部分内容时,我的第一反应是:难道同学们以为做技术管理不需要很好的技术功底?刚好在此之前,我写过《技术敏感度 — 基层技术管理者必备》一文,强调技术功底对于基层技术管理者的重要性。于是,我对该条微博评论了:“建议邹老师建议他们好好地学一学技术,技术的精进一定会让我们或多或少地贯通管理(掌握软件开发的常识)。对于真要做管理的,建议他们在以后摆好心态 — 承认自己对技术的‘无知’,以及充分尊重技术人才并放权于他们”。之后,邹欣老师帮同学们提了一个让人深思的问题 — “技术有很多,有些技术还会过时,你具体指哪些技术呢?”某种程度上,这问题可以理解为是问:“终极技术”是什么?

在执笔本文时,我总觉得以前写过类似的文章。查了一下,两年前的确以《软件开发,到底应当学什么?》为题写过了一篇博文。不过,过去的两年我又有了新的收获,或许可以借此机会再梳理一下自己的认识,以便与大家分享。
身处节奏很快的IT行业,软件工程师一定希望自己在职业发展的道路上掌握“终极技术”,以便将来即使“长江后浪推前浪”仍能获得竞争优势。掌握“终极技术”对于我们究竟意味着什么?深刻理解这一问题有助于我们在面对技术学习和技术选择时不至于迷茫或人云亦云。我认为,掌握“终极技术”的最终目的不是为了能在工作中“耍酷”(“哇,这问题其他哥们都搞不定,只有我能!”),也不是为了追赶“技术潮流”(“听说Go语言以后能替代C/C++和Java,我得赶快去学!”),而是为了高质高效地工作,因为只有这样才能提高我们的生活品质和减少浪费(浪费可能包括奢华的青春和/或宝贵的社会资源)。
实际上,我们一生都是在工作质量和工作效率的二维坐标系上“画线”。有的人一生都难以走出低质低效的困境(比如下图中黑色曲线所代表的人),而有的人却能进入高质高效的殿堂(比如下图中红色曲线所代表的人)。
明白了掌握“终极技术”的意义,那“终极技术”究竟是什么?会是C/C++、Java、Objective-C或Go等编程语言吗?当一个只精通C/C++编程语言的人加入到以Objective-C为编程语言的项目上时,显然他必须重新学习编程语言。由此看来编程语言因为对不同的项目并不具备普适性,难以拥有“终极技术”之名。对于网上不少为编程语言而打口水仗的人,我真怀疑他们将编程语言当作是“终极技术”了。一旦知晓了“终极技术”的存在,你一定会发现,其实所谓的编程语言“优劣”跟本就不是业内的大问题。如果某种语言直接导致了项目的失败,那该语言早就绝迹了;反过来,如果某种语言直接导致了项目的成功,那世界上估计也只会有这一种语言了。因此,选择编程语言的重点不是考究其“优劣”,而是其适用性。过分计较编程语言的“优劣”其实是不成熟的一种表现。这类人还容易犯的一个毛病是 — 生怕落后,热衷于学习新的编程语言。请别忘了,编程语言我们无论如何也学不全,即使真有人学全了,我也怀疑他所学的只是皮毛。
“终极技术”又会是Linux或Windows这样的操作系统平台吗?由于它们同样不具普适性,所以不可能有“终极技术”之实。同样地,.Net、ACE、QT等都不可能是“终极技术”。
真正的“终极技术”一定具有一定的普适性,能让我们将之运用于各种不同的软件项目。正因如此,“终极技术”具有一定的抽象性。对于软件行业来说,真正掌握“终极技术”意味着:深刻地理解软件(开发)的复杂性本质,并拥有有助于实现高质高效工作的行为(意识、工作习惯等)、能力(思维、业务、沟通)和方法(流程、工具、复用)。
由于“终极技术”过于抽象,使得我们不得不通过一些问题来间接感知。比如:
1)编程好习惯对于软件产品的质量重要吗?如果重要,如何让团队形成良好的编程习惯?哪些编程习惯算是好的?
2)软件质量的根本是什么?是设计,抑或测试?高质量的软件对工程师的工作与生活又意味着什么?
3)软件架构师重要吗?还是只是个虚职?如果重要,软件架构师需要掌握哪些技能?
4)在软件行业具有很大影响力的CMM(软件成熟度模型),其倡导用软件过程的成熟度来度量组织的软件开发能力。那为什么通过CMM最高级别认证的组织仍会开发出质量一塌糊涂的软件?如果你身临其中,能发现导致这种糟糕结果的关键因素吗?
5)软件平台与框架被广泛地认为是高效开发高质软件的方法,但为什么企业运用这一方法后,平台与框架最终却成了一个包袱?困境的表现是什么?什么因素造成了这种困境?有方法避免进入这种困境吗?
6)业内大量使用“最佳实践”这一词汇。真正存在最佳实践吗?为什么有的“最佳实践”在组织中却无效?
7)……
这些问题大多是开放性的,而且不少问题既涉及管理域,又涉及技术域。面对这些问题的关键不在于其是否有标准答案(或许根本没有标准答案),而在于我们是否为之痛苦过、思考过,并形成了自己的想法。要知道,这些想法就是我们在工作中面对选择时用作决策的依据。如果从来没有这类苦恼,很难想象我们真正掌握了“终极技术”。值得一提的是,这些问题只是基于我自己肤浅的认识所提出的,我相信读者还有很多类似或其他的问题。
如果将软件(开发)的复杂性比喻为一头大象,那么我们每一个人或许是正在摸象的又瞎又聋的人,我们穷一生通过“摸”的方式,在头脑中构建“象”的模样。这个比喻间接地告诉我们,“终极技术”并非是某种一成不变的内容,其中更涵盖有每个人根据自己的阅历所总结出来的在高质高效工作道路上成功应对困境的方法和信念。
“终极技术”一定是通过掌握象编程语言等非“终极技术”而最终掌握的,也需要我们通过经受软件项目的痛苦磨砺去沉淀。在没有掌握“终极技术”之前,请不要停留在编程语言专家、Linux内核专家、.Net专家这样的光环之下,继续探索,前面还有更大的舞台等着你!在掌握“终极技术”的职场旅途中,我们得先认识到一点:就技术内容而言,职场首先比拼的并不是智商,而是我们的坚持与良好的工作习惯。工作中的很多道理我们都懂,但就是不能坚持做到深究,也难以通过坚持克服陋习去形成更多的好习惯。在掌握“终极技术”的道路上,我们一定会看到很多不尽人意的内容,也会面临不少困难与挫折,即使理智上悲观,但我们在行动和意志上一定要保持乐观(注:Antonio Gramsci的原话是“理智上悲观,意志上乐观”)。

(转)微博数据库设计

部分功能建表设计

Users用户注册信息表

描述 字段名 类型 空值 其他
用户ID user_id number(8) 主键
用户邮箱 user_email varchar(40)  
用户密码 user_password varchar(80)  
用户昵称 user_nikename varchar(60)  
注册时间 user_time timestamp  
验证状态 user_status Number(1)   默认(0)

 

 

Userinfo 用户详细信息表

描述 字段名 类型 空值 其他
用户资料ID userinfo_id number(8) 主键
真实姓名 userinfo_truename varchar(40)    
所在地 userinfo_address varchar(120)    
性别 userinfo_sex varchar(4)    
性取向 userinfo_sexual varchar(8)    
感情状况 userinfo_feeling varchar(20)    
生日 userinfo_birthday varchar(20)    
血型 userinfo_bloodtype varchar(8)    
博客地址 userinfo_blogurl varchar(200)    
个性域名 userinfo_realmname varchar(200)    
简介 userinfo_intro varchar(400)    
邮箱 userinfo_email varchar(60)    
QQ userinfo_qqnumber varchar(30)    
MSN userinfo_messenger varchar(60)    
职业信息 userinfo_profession varchar(60)    
标签 userinfo_label varchar(200)    
用户ID user_id number(8) 外键

 

 

Relation 用户关系表

描述 字段名 类型 空值 其他
用户关系ID relation_id number(8) 主键
创建时间 relation_time timestamp    
关系类型 relation_type varchar(20)    
关系组名 relation_ groupname varchar(20)    
用户ID user_id number(8) 外键
被关注用户 user_byid number(8) 外键

 

 

Messages 微博表

描述 字段名 类型 空值 其他
普通消息ID messages_id number(8) 主键
消息类型 messages_type varchar(20)    
消息内容 messages_info varchar(400)    
发表时间 messages_time timestamp    
收藏次数 messages_collectnum number(8)    
评论次数 messages_commentnum number(8)    
转发次数 messages_ transpondnum number(8)    
赞同次数 messages_agreenum number(8)    
阅读次数 messages_readnum number(8)    
消息标签 messages_label varchar(80)    
消息图片ID picture_id number(8) 外键
发表用户ID user_id number(8) 外键

 

 

Atusers被at用户表

描述 字段名 类型 空值 其他
ID atusers_id number(8) 主键
普通消息ID messages_id number(8) 外键
被at用户ID user_atid number(8) 外键
被at时间 atusers_time timestamp    

 

 

Collections 微博收藏表

描述 字段名 类型 空值 其他
收藏ID collections_id number(8) 主键
收藏时间 collections_time timestamp    
收藏状态 collections_status varchar(10)  
收藏用户ID user_id number(8)    
普通消息ID messages_id number(8) 外键

 

 

Privateletter私信表

描述 字段名 类型 空值 其他
私信ID privateletter_id number(8) 主键
私信内容 privateletter_info varchar(400)    
内容状态 privateletter_infostatus varchar(10)  
发送时间 privateletter_time timestamp    
发送用户ID user_id number(8) 外键
接受用户ID user_id number(8) 外键

 

 

Comments 评论表

描述 字段名 类型 空值 其他
评论ID comments_id number(8) 主键
评论内容 comments_info varchar(200)    
内容状态 comments_infostatus varchar(10)    
评论时间 comments_time timestamp    
普通消息ID messages_id number(8) 外键
用户ID user_id number(8) 外键

 

 

Pictures 图片表

描述 字段名 类型 空值 其他
图片ID picture_id number(8) 主键
图片地址 picture_url varchar(200)    
图片类别 picture_type varchar(20)    
图片时间 picture_time timestamp    
用户ID user_id number(8) 外键

 

 

Admins管理员表

描述 字段名 类型 空值 其他
管理员ID admins_id number(8) 主键
管理员名称 admins_name varchar(20)  
管理员密码 admins_pass varchar(20)  

 

转载文章请注明出处:http://blog.csdn.net/chrp99

(转)一步步构建大型网站架构

(转)一步步构建大型网站架构

 

之前我简单向大家介绍了各个知名大型网站的架构,亿万用户网站MySpace的成功秘密Flickr架构YouTube网站架构PlentyOfFish 网站架构学习WikiPedia技术架构学习笔记。这几个都很典型,我们可以从中获取很多有关网站架构方面的知识,看了之后你会发现你原来的想法很可能是狭隘的。

今天我们来谈谈一个网站一般是如何一步步来构建起系统架构的,虽然我们希望网站一开始就能有一个很好的架构,但马克思告诉我们事物是在发展中不断前进的,网站架构也是随着业务的扩大、用户的需求不断完善的,下面是一个网站架构逐步发展的基本过程,读完后,请思考,你现在在哪个阶段。

  架构演变第一步:物理分离WebServer和数据库

最开始,由于某些想法,于是在互联网上搭建了一个网站,这个时候甚至有可能主机都是租借的,但由于这篇文章我们只关注架构的演变历程,因此就假设这个时候已经是托管了一台主机,并且有一定的带宽了。这个时候由于网站具备了一定的特色,吸引了部分人访问,逐渐你发现系统的压力越来越高,响应速度越来越慢,而这个时候比较明显的是数据库和应用互相影响,应用出问题了,数据库也很容易出现问题,而数据库出问题的时候,应用也容易出问题。于是进入了第一步演变阶段:将应用和数据库从物理上分离,变成了两台机器,这个时候技术上没有什么新的要求,但你发现确实起到效果了,系统又恢复到以前的响应速度了,并且支撑住了更高的流量,并且不会因为数据库和应用形成互相的影响。

看看这一步完成后系统的图示:

  架构演变第二步:增加页面缓存

好景不长,随着访问的人越来越多,你发现响应速度又开始变慢了,查找原因,发现是访问数据库的操作太多,导致数据连接竞争激烈,所以响应变慢。但数据库连接又不能开太多,否则数据库机器压力会很高,因此考虑采用缓存机制来减少数据库连接资源的竞争和对数据库读的压力。这个时候首先也许会选择采用squid等类似的机制来将系统中相对静态的页面(例如一两天才会有更新的页面)进行缓存(当然,也可以采用将页面静态化的方案),这样程序上可以不做修改,就能够很好的减少对WebServer的压力以及减少数据库连接资源的竞争,OK,于是开始采用squid来做相对静态的页面的缓存。

看看这一步完成后系统的图示:

这一步涉及到了这些知识体系:

前端页面缓存技术,例如squid,如想用好的话还得深入掌握下squid的实现方式以及缓存的失效算法等。

  架构演变第三步:增加页面片段缓存

增加了squid做缓存后,整体系统的速度确实是提升了,WebServer的压力也开始下降了,但随着访问量的增加,发现系统又开始变的有些慢了。在尝到了squid之类的动态缓存带来的好处后,开始想能不能让现在那些动态页面里相对静态的部分也缓存起来呢,因此考虑采用类似ESI之类的页面片段缓存策略,OK,于是开始采用ESI来做动态页面中相对静态的片段部分的缓存。

看看这一步完成后系统的图示:

这一步涉及到了这些知识体系:

页面片段缓存技术,例如ESI等,想用好的话同样需要掌握ESI的实现方式等;

  架构演变第四步:数据缓存

在采用ESI之类的技术再次提高了系统的缓存效果后,系统的压力确实进一步降低了,但同样,随着访问量的增加,系统还是开始变慢。经过查找,可能会发现系统中存在一些重复获取数据信息的地方,像获取用户信息等,这个时候开始考虑是不是可以将这些数据信息也缓存起来呢,于是将这些数据缓存到本地内存,改变完毕后,完全符合预期,系统的响应速度又恢复了,数据库的压力也再度降低了不少。

看看这一步完成后系统的图示:

这一步涉及到了这些知识体系:

缓存技术,包括像Map数据结构、缓存算法、所选用的框架本身的实现机制等。

  架构演变第五步: 增加WebServer

好景不长,发现随着系统访问量的再度增加,webserver机器的压力在高峰期会上升到比较高,这个时候开始考虑增加一台webserver,这也是为了同时解决可用性的问题,避免单台的webserver down机的话就没法使用了,在做了这些考虑后,决定增加一台webserver,增加一台webserver时,会碰到一些问题,典型的有:
1、如何让访问分配到这两台机器上,这个时候通常会考虑的方案是Apache自带的负载均衡方案,或LVS这类的软件负载均衡方案;
2、如何保持状态信息的同步,例如用户session等,这个时候会考虑的方案有写入数据库、写入存储、cookie或同步session信息等机制等;
3、如何保持数据缓存信息的同步,例如之前缓存的用户数据等,这个时候通常会考虑的机制有缓存同步或分布式缓存;
4、如何让上传文件这些类似的功能继续正常,这个时候通常会考虑的机制是使用共享文件系统或存储等;
在解决了这些问题后,终于是把webserver增加为了两台,系统终于是又恢复到了以往的速度。

看看这一步完成后系统的图示:

这一步涉及到了这些知识体系:

负载均衡技术(包括但不限于硬件负载均衡、软件负载均衡、负载算法、linux转发协议、所选用的技术的实现细节等)、主备技术(包括但不限于ARP欺骗、linuxheart-beat等)、状态信息或缓存同步技术(包括但不限于Cookie技术、UDP协议、状态信息广播、所选用的缓存同步技术的实现细节等)、共享文件技术(包括但不限于NFS等)、存储技术(包括但不限于存储设备等)。

  架构演变第六步:分库

享受了一段时间的系统访问量高速增长的幸福后,发现系统又开始变慢了,这次又是什么状况呢,经过查找,发现数据库写入、更新的这些操作的部分数据库连接的资源竞争非常激烈,导致了系统变慢,这下怎么办呢?此时可选的方案有数据库集群和分库策略,集群方面像有些数据库支持的并不是很好,因此分库会成为比较普遍的策略,分库也就意味着要对原有程序进行修改,一通修改实现分库后,不错,目标达到了,系统恢复甚至速度比以前还快了。

看看这一步完成后系统的图示:

这一步涉及到了这些知识体系:

这一步更多的是需要从业务上做合理的划分,以实现分库,具体技术细节上没有其他的要求;

但同时随着数据量的增大和分库的进行,在数据库的设计、调优以及维护上需要做的更好,因此对这些方面的技术还是提出了很高的要求的。

  架构演变第七步:分表、DAL和分布式缓存

  随着系统的不断运行,数据量开始大幅度增长,这个时候发现分库后查询仍然会有些慢,于是按照分库的思想开始做分表的工作。当然,这不可避免的会需要对程序进行一些修改,也许在这个时候就会发现应用自己要关心分库分表的规则等,还是有些复杂的。于是萌生能否增加一个通用的框架来实现分库分表的数据访问,这个在ebay的架构中对应的就是DAL,这个演变的过程相对而言需要花费较长的时间。当然,也有可能这个通用的框架会等到分表做完后才开始做。同时,在这个阶段可能会发现之前的缓存同步方案出现问题,因为数据量太大,导致现在不太可能将缓存存在本地,然后同步的方式,需要采用分布式缓存方案了。于是,又是一通考察和折磨,终于是将大量的数据缓存转移到分布式缓存上了。

看看这一步完成后系统的图示:

这一步涉及到了这些知识体系:

分表更多的同样是业务上的划分,技术上涉及到的会有动态hash算法、consistenthash算法等;

DAL涉及到比较多的复杂技术,例如数据库连接的管理(超时、异常)、数据库操作的控制(超时、异常)、分库分表规则的封装等;

  架构演变第八步:增加更多的WebServer

在做完分库分表这些工作后,数据库上的压力已经降到比较低了,又开始过着每天看着访问量暴增的幸福生活了。突然有一天,发现系统的访问又开始有变慢的趋势 了,这个时候首先查看数据库,压力一切正常,之后查看webserver,发现apache阻塞了很多的请求,而应用服务器对每个请求也是比较快的,看来是请求数太高导致需要排队等待,响应速度变慢。这还好办,一般来说,这个时候也会有些钱了,于是添加一些webserver服务器,在这个添加webserver服务器的过程,有可能会出现几种挑战:

1、Apache的软负载或LVS软负载等无法承担巨大的web访问量(请求连接数、网络流量等)的调度了,这个时候如果经费允许的话,会采取的方案是购买硬件负载平衡设备,例如F5、Netsclar、Athelon之类的,如经费不允许的话,会采取的方案是将应用从逻辑上做一定的分类,然后分散到不同的软负载集群中;

2、原有的一些状态信息同步、文件共享等方案可能会出现瓶颈,需要进行改进,也许这个时候会根据情况编写符合网站业务需求的分布式文件系统等;

在做完这些工作后,开始进入一个看似完美的无限伸缩的时代,当网站流量增加时,应对的解决方案就是不断的添加webserver。

看看这一步完成后系统的图示:

这一步涉及到了这些知识体系:

到了这一步,随着机器数的不断增长、数据量的不断增长和对系统可用性的要求越来越高,这个时候要求对所采用的技术都要有更为深入的理解,并需要根据网站的需求来做更加定制性质的产品。

  架构演变第九步:数据读写分离和廉价存储方案

突然有一天,发现这个完美的时代也要结束了,数据库的噩梦又一次出现在眼前了。由于添加的webserver太多了,导致数据库连接的资源还是不够用,而这个时候又已经分库分表了,开始分析数据库的压力状况,可能会发现数据库的读写比很高,这个时候通常会想到数据读写分离的方案。当然,这个方案要实现并不容易,另外,可能会发现一些数据存储在数据库上有些浪费,或者说过于占用数据库资源,因此在这个阶段可能会形成的架构演变是实现数据读写分离,同时编写一些更为廉价的存储方案,例如BigTable这种。

看看这一步完成后系统的图示:

这一步涉及到了这些知识体系:

数据读写分离要求对数据库的复制、standby等策略有深入的掌握和理解,同时会要求具备自行实现的技术;

廉价存储方案要求对OS的文件存储有深入的掌握和理解,同时要求对采用的语言在文件这块的实现有深入的掌握。

  架构演变第十步:进入大型分布式应用时代和廉价服务器群梦想时代

经过上面这个漫长而痛苦的过程,终于是再度迎来了完美的时代,不断的增加webserver就可以支撑越来越高的访问量了。对于大型网站而言,人气的重要毋庸置疑,随着人气的越来越高,各种各样的功能需求也开始爆发性的增长。这个时候突然发现,原来部署在webserver上的那个web应用已经非常庞大 了,当多个团队都开始对其进行改动时,可真是相当的不方便,复用性也相当糟糕,基本是每个团队都做了或多或少重复的事情,而且部署和维护也是相当的麻烦。因为庞大的应用包在N台机器上复制、启动都需要耗费不少的时间,出问题的时候也不是很好查,另外一个更糟糕的状况是很有可能会出现某个应用上的bug就导 致了全站都不可用,还有其他的像调优不好操作(因为机器上部署的应用什么都要做,根本就无法进行针对性的调优)等因素,根据这样的分析,开始痛下决心,将系统根据职责进行拆分,于是一个大型的分布式应用就诞生了,通常,这个步骤需要耗费相当长的时间,因为会碰到很多的挑战:

1、拆成分布式后需要提供一个高性能、稳定的通信框架,并且需要支持多种不同的通信和远程调用方式;
2、将一个庞大的应用拆分需要耗费很长的时间,需要进行业务的整理和系统依赖关系的控制等;
3、如何运维(依赖管理、运行状况管理、错误追踪、调优、监控和报警等)好这个庞大的分布式应用。
经过这一步,差不多系统的架构进入相对稳定的阶段,同时也能开始采用大量的廉价机器来支撑着巨大的访问量和数据量,结合这套架构以及这么多次演变过程吸取的经验来采用其他各种各样的方法来支撑着越来越高的访问量。

看看这一步完成后系统的图示:

这一步涉及到了这些知识体系:

这一步涉及的知识体系非常的多,要求对通信、远程调用、消息机制等有深入的理解和掌握,要求的都是从理论、硬件级、操作系统级以及所采用的语言的实现都有清楚的理解。

最后,附上一张大型网站的架构图:

原文地址:http://developer.51cto.com/art/200810/91460.htm

一位老鸟对 23 种设计模式的有趣见解

一位老鸟对 23 种设计模式的有趣见解

 

在网络上流畅很广的一篇旧文,暂时没找到原作者,目前所看到的最早转载时间是 2005 年 2 月 28 日。作者用轻松的语言,形象解释了 23 种模式,有很好的启发作用。

创建型模式

1、FACTORY—追MM少不了请吃饭了,麦当劳的鸡翅和肯德基的鸡翅都是MM爱吃的东西,虽然口味有所不同,但不管你带MM去麦当劳或肯德基,只管向服务员说“来四个鸡翅”就行了。麦当劳和肯德基就是生产鸡翅的Factory

  工厂模式:客户类和工厂类分开。消费者任何时候需要某种产品,只需向工厂请求即可。消费者无须修改就可以接纳新产品。缺点是当产品修改时,工厂类也要做相应的修改。如:如何创建及如何向客户端提供。

2、BUILDER—MM最爱听的就是“我爱你”这句话了,见到不同地方的MM,要能够用她们的方言跟她说这句话哦,我有一个多种语言翻译机,上面每种语言都有一个按键,见到MM我只要按对应的键,它就能够用相应的语言说出“我爱你”这句话了,国外的MM也可以轻松搞掂,这就是我的“我爱你”builder。(这一定比美军在伊拉克用的翻译机好卖)

         建造模式:将产品的内部表象和产品的生成过程分割开来,从而使一个建造过程生成具有不同的内部表象的产品对象。建造模式使得产品内部表象可以独立的变化,客户不必知道产品内部组成的细节。建造模式可以强制实行一种分步骤进行的建造过程。

3、FACTORY METHOD—请MM去麦当劳吃汉堡,不同的MM有不同的口味,要每个都记住是一件烦人的事情,我一般采用Factory Method模式,带着MM到服务员那儿,说“要一个汉堡”,具体要什么样的汉堡呢,让MM直接跟服务员说就行了。

  工厂方法模式:核心工厂类不再负责所有产品的创建,而是将具体创建的工作交给子类去做,成为一个抽象工厂角色,仅负责给出具体工厂类必须实现的接口,而不接触哪一个产品类应当被实例化这种细节。

4、PROTOTYPE—跟MM用QQ聊天,一定要说些深情的话语了,我搜集了好多肉麻的情话,需要时只要copy出来放到QQ里面就行了,这就是我的情话prototype了。(100块钱一份,你要不要)

原始模型模式:通过给出一个原型对象来指明所要创建的对象的类型,然后用复制这个原型对象的方法创建出更多同类型的对象。原始模型模式允许动态的增加或减少产品类,产品类不需要非得有任何事先确定的等级结构,原始模型模式适用于任何的等级结构。缺点是每一个类都必须配备一个克隆方法。

5、SINGLETON—俺有6个漂亮的老婆,她们的老公都是我,我就是我们家里的老公Sigleton,她们只要说道“老公”,都是指的同一个人,那就是我(刚才做了个梦啦,哪有这么好的事)

单例模式:单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例单例模式。单例模式只应在有真正的“单一实例”的需求时才可使用。

结构型模式

6、ADAPTER—在朋友聚会上碰到了一个美女Sarah,从香港来的,可我不会说粤语,她不会说普通话,只好求助于我的朋友kent了,他作为我和Sarah之间的Adapter,让我和Sarah可以相互交谈了(也不知道他会不会耍我)

适配器(变压器)模式:把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口原因不匹配而无法一起工作的两个类能够一起工作。适配类可以根据参数返还一个合适的实例给客户端。

7、BRIDGE—早上碰到MM,要说早上好,晚上碰到MM,要说晚上好;碰到MM穿了件新衣服,要说你的衣服好漂亮哦,碰到MM新做的发型,要说你的头发好漂亮哦。不要问我“早上碰到MM新做了个发型怎么说”这种问题,自己用BRIDGE组合一下不就行了

桥梁模式:将抽象化与实现化脱耦,使得二者可以独立的变化,也就是说将他们之间的强关联变成弱关联,也就是指在一个软件系统的抽象化和实现化之间使用组合/聚合关系而不是继承关系,从而使两者可以独立的变化。

8、COMPOSITE—Mary今天过生日。“我过生日,你要送我一件礼物。”“嗯,好吧,去商店,你自己挑。”“这件T恤挺漂亮,买,这条裙子好看,买,这个包也不错,买。”“喂,买了三件了呀,我只答应送一件礼物的哦。”“什么呀,T恤加裙子加包包,正好配成一套呀,小姐,麻烦你包起来。”“……”,MM都会用Composite模式了,你会了没有?

合成模式:合成模式将对象组织到树结构中,可以用来描述整体与部分的关系。合成模式就是一个处理对象的树结构的模式。合成模式把部分与整体的关系用树结构表示出来。合成模式使得客户端把一个个单独的成分对象和由他们复合而成的合成对象同等看待。

9、DECORATOR—Mary过完轮到Sarly过生日,还是不要叫她自己挑了,不然这个月伙食费肯定玩完,拿出我去年在华山顶上照的照片,在背面写上“最好的的礼物,就是爱你的Fita”,再到街上礼品店买了个像框(卖礼品的MM也很漂亮哦),再找隔壁搞美术设计的Mike设计了一个漂亮的盒子装起来……,我们都是Decorator,最终都在修饰我这个人呀,怎么样,看懂了吗?

       装饰模式:装饰模式以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案,提供比继承更多的灵活性。动态给一个对象增加功能,这些功能可以再动态的撤消。增加由一些基本功能的排列组合而产生的非常大量的功能。

10、FACADE—我有一个专业的Nikon相机,我就喜欢自己手动调光圈、快门,这样照出来的照片才专业,但MM可不懂这些,教了半天也不会。幸好相机有Facade设计模式,把相机调整到自动档,只要对准目标按快门就行了,一切由相机自动调整,这样MM也可以用这个相机给我拍张照片了。

  门面模式:外部与一个子系统的通信必须通过一个统一的门面对象进行。门面模式提供一个高层次的接口,使得子系统更易于使用。每一个子系统只有一个门面类,而且此门面类只有一个实例,也就是说它是一个单例模式。但整个系统可以有多个门面类。

11、FLYWEIGHT—每天跟MM发短信,手指都累死了,最近买了个新手机,可以把一些常用的句子存在手机里,要用的时候,直接拿出来,在前面加上MM的名字就可以发送了,再不用一个字一个字敲了。共享的句子就是Flyweight,MM的名字就是提取出来的外部特征,根据上下文情况使用。

  享元模式:FLYWEIGHT在拳击比赛中指最轻量级。享元模式以共享的方式高效的支持大量的细粒度对象。享元模式能做到共享的关键是区分内蕴状态和外蕴状态。内蕴状态存储在享元内部,不会随环境的改变而有所不同。外蕴状态是随环境的改变而改变的。外蕴状态不能影响内蕴状态,它们是相互独立的。将可以共享的状态和不可以共享的状态从常规类中区分开来,将不可以共享的状态从类里剔除出去。客户端不可以直接创建被共享的对象,而应当使用一个工厂对象负责创建被共享的对象。享元模式大幅度的降低内存中对象的数量。

12、PROXY—跟MM在网上聊天,一开头总是“hi,你好”,“你从哪儿来呀?”“你多大了?”“身高多少呀?”这些话,真烦人,写个程序做为我的Proxy吧,凡是接收到这些话都设置好了自动的回答,接收到其他的话时再通知我回答,怎么样,酷吧。

        代理模式:代理模式给某一个对象提供一个代理对象,并由代理对象控制对源对象的引用。代理就是一个人或一个机构代表另一个人或者一个机构采取行动。某些情况下,客户不想或者不能够直接引用一个对象,代理对象可以在客户和目标对象直接起到中介的作用。客户端分辨不出代理主题对象与真实主题对象。代理模式可以并不知道真正的被代理对象,而仅仅持有一个被代理对象的接口,这时候代理对象不能够创建被代理对象,被代理对象必须有系统的其他角色代为创建并传入。

行为模式

13、CHAIN OF RESPONSIBLEITY—晚上去上英语课,为了好开溜坐到了最后一排,哇,前面坐了好几个漂亮的MM哎,找张纸条,写上“Hi,可以做我的女朋友吗?如果不愿意请向前传”,纸条就一个接一个的传上去了,糟糕,传到第一排的MM把纸条传给老师了,听说是个老处女呀,快跑!

责任链模式:在责任链模式中,很多对象由每一个对象对其下家的引用而接

起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。客户并不知道链上的哪一个对象最终处理这个请求,系统可以在不影响客户端的情况下动态的重新组织链和分配责任。处理者有两个选择:承担责任或者把责任推给下家。一个请求可以最终不被任何接收端对象所接受。

14、COMMAND—俺有一个MM家里管得特别严,没法见面,只好借助于她弟弟在我们俩之间传送信息,她对我有什么指示,就写一张纸条让她弟弟带给我。这不,她弟弟又传送过来一个COMMAND,为了感谢他,我请他吃了碗杂酱面,哪知道他说:“我同时给我姐姐三个男朋友送COMMAND,就数你最小气,才请我吃面。”,:-(

命令模式:命令模式把一个请求或者操作封装到一个对象中。命令模式把发出命令的责任和执行命令的责任分割开,委派给不同的对象。命令模式允许请求的一方和发送的一方独立开来,使得请求的一方不必知道接收请求的一方的接口,更不必知道请求是怎么被接收,以及操作是否执行,何时被执行以及是怎么被执行的。系统支持命令的撤消。

15、INTERPRETER—俺有一个《泡MM真经》,上面有各种泡MM的攻略,比如说去吃西餐的步骤、去看电影的方法等等,跟MM约会时,只要做一个Interpreter,照着上面的脚本执行就可以了。

        解释器模式:给定一个语言后,解释器模式可以定义出其文法的一种表示,并同时提供一个解释器。客户端可以使用这个解释器来解释这个语言中的句子。解释器模式将描述怎样在有了一个简单的文法后,使用模式设计解释这些语句。在解释器模式里面提到的语言是指任何解释器对象能够解释的任何组合。在解释器模式中需要定义一个代表文法的命令类的等级结构,也就是一系列的组合规则。每一个命令对象都有一个解释方法,代表对命令对象的解释。命令对象的等级结构中的对象的任何排列组合都是一个语言。

16、ITERATOR—我爱上了Mary,不顾一切的向她求婚。
Mary:“想要我跟你结婚,得答应我的条件”
我:“什么条件我都答应,你说吧”
Mary:“我看上了那个一克拉的钻石”
我:“我买,我买,还有吗?”
Mary:“我看上了湖边的那栋别墅”
我:“我买,我买,还有吗?”
Mary:“你的小弟弟必须要有50cm长”
我脑袋嗡的一声,坐在椅子上,一咬牙:“我剪,我剪,还有吗?”
……

  迭代子模式:迭代子模式可以顺序访问一个聚集中的元素而不必暴露聚集的内部表象。多个对象聚在一起形成的总体称之为聚集,聚集对象是能够包容一组对象的容器对象。迭代子模式将迭代逻辑封装到一个独立的子对象中,从而与聚集本身隔开。迭代子模式简化了聚集的界面。每一个聚集对象都可以有一个或一个以上的迭代子对象,每一个迭代子的迭代状态可以是彼此独立的。迭代算法可以独立于聚集角色变化。

17、MEDIATOR—四个MM打麻将,相互之间谁应该给谁多少钱算不清楚了,幸亏当时我在旁边,按照各自的筹码数算钱,赚了钱的从我这里拿,赔了钱的也付给我,一切就OK啦,俺得到了四个MM的电话。

   调停者模式:调停者模式包装了一系列对象相互作用的方式,使得这些对象不必相互明显作用。从而使他们可以松散偶合。当某些对象之间的作用发生改变时,不会立即影响其他的一些对象之间的作用。保证这些作用可以彼此独立的变化。调停者模式将多对多的相互作用转化为一对多的相互作用。调停者模式将对象的行为和协作抽象化,把对象在小尺度的行为上与其他对象的相互作用分开处理。

18、MEMENTO—同时跟几个MM聊天时,一定要记清楚刚才跟MM说了些什么话,不然MM发现了会不高兴的哦,幸亏我有个备忘录,刚才与哪个MM说了什么话我都拷贝一份放到备忘录里面保存,这样可以随时察看以前的记录啦。

   备忘录模式:备忘录对象是一个用来存储另外一个对象内部状态的快照的对象。备忘录模式的用意是在不破坏封装的条件下,将一个对象的状态捉住,并外部化,存储起来,从而可以在将来合适的时候把这个对象还原到存储起来的状态。

19、OBSERVER—想知道咱们公司最新MM情报吗?加入公司的MM情报邮件组就行了,tom负责搜集情报,他发现的新情报不用一个一个通知我们,直接发布给邮件组,我们作为订阅者(观察者)就可以及时收到情报啦

   观察者模式:观察者模式定义了一种一队多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态上发生变化时,会通知所有观察者对象,使他们能够自动更新自己。

20、STATE—跟MM交往时,一定要注意她的状态哦,在不同的状态时她的行为会有不同,比如你约她今天晚上去看电影,对你没兴趣的MM就会说“有事情啦”,对你不讨厌但还没喜欢上的MM就会说“好啊,不过可以带上我同事么?”,已经喜欢上你的MM就会说“几点钟?看完电影再去泡吧怎么样?”,当然你看电影过程中表现良好的话,也可以把MM的状态从不讨厌不喜欢变成喜欢哦。

状态模式:状态模式允许一个对象在其内部状态改变的时候改变行为。这个对象看上去象是改变了它的类一样。状态模式把所研究的对象的行为包装在不同的状态对象里,每一个状态对象都属于一个抽象状态类的一个子类。状态模式的意图是让一个对象在其内部状态改变的时候,其行为也随之改变。状态模式需要对每一个系统可能取得的状态创立一个状态类的子类。当系统的状态变化时,系统便改变所选的子类。

21、STRATEGY—跟不同类型的MM约会,要用不同的策略,有的请电影比较好,有的则去吃小吃效果不错,有的去海边浪漫最合适,单目的都是为了得到MM的芳心,我的追MM锦囊中有好多Strategy哦。

策略模式:策略模式针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换。策略模式使得算法可以在不影响到客户端的情况下发生变化。策略模式把行为和环境分开。环境类负责维持和查询行为类,各种算法在具体的策略类中提供。由于算法和环境独立开来,算法的增减,修改都不会影响到环境和客户端。

22、TEMPLATE METHOD——看过《如何说服女生上床》这部经典文章吗?女生从认识到上床的不变的步骤分为巧遇、打破僵局、展开追求、接吻、前戏、动手、爱抚、进去八大步骤(Template method),但每个步骤针对不同的情况,都有不一样的做法,这就要看你随机应变啦(具体实现);

  模板方法模式:模板方法模式准备一个抽象类,将部分逻辑以具体方法以及具体构造子的形式实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑。不同的子类可以以不同的方式实现这些抽象方法,从而对剩余的逻辑有不同的实现。先制定一个顶级逻辑框架,而将逻辑的细节留给具体的子类去实现。

23、VISITOR—情人节到了,要给每个MM送一束鲜花和一张卡片,可是每个MM送的花都要针对她个人的特点,每张卡片也要根据个人的特点来挑,我一个人哪搞得清楚,还是找花店老板和礼品店老板做一下Visitor,让花店老板根据MM的特点选一束花,让礼品店老板也根据每个人特点选一张卡,这样就轻松多了;

访问者模式:访问者模式的目的是封装一些施加于某种数据结构元素之上的操作。一旦这些操作需要修改的话,接受这个操作的数据结构可以保持不变。访问者模式适用于数据结构相对未定的系统,它把数据结构和作用于结构上的操作之间的耦合解脱开,使得操作集合可以相对自由的演化。访问者模式使得增加新的操作变的很容易,就是增加一个新的访问者类。访问者模式将有关的行为集中到一个访问者对象中,而不是分散到一个个的节点类中。当使用访问者模式时,要将尽可能多的对象浏览逻辑放在访问者类中,而不是放到它的子类中。访问者模式可以跨过几个类的等级结构访问属于不同的等级结构的成员类。

(转)各大网站架构简单总结[分享]

各大网站架构简单总结[分享]

1、Facebook架构
大体层次划分,Facebook的架构可以从不同角度来换分层次。一种是:一边是PHP整的经典的LAMP stack;另外一个是非PHP整的各种service。
–Web 前端是由 PHP 写的。Facebook 的HipHop会把PHP转成C++并用g++编译,这样就可以为模板和Web逻贺业务层提供高的性能。
–业务逻辑以Service的形式存在,其使用Thrift。这些Service根据需求的不同由PHP,C++或Java实现(也可以用到了其它的一些语言……)
–持久化由MySQL, Memcached, Facebook的Cassandra, Hadoop的HBase完成。Memcached使用了MySQL的内存Cache。Facebook工程师承认他们的Cassandra使用正在减少,因为他们更喜欢HBase,因为它的更简单的一致性模型,以到其MapReduce能力。

2、Flickr网站架构总结

Flickr.com是网上最受欢迎的照片共享网站之一,还记得那位给Windows Vista拍摄壁纸的Hamad Darwish吗?他就是将照片上传到Flickr,后而被微软看中成为Vista壁纸御用摄影师。

–Pair of ServerIron’s做负载均衡

–Squid做html和照片的缓存

–Memcached做数据缓存

–尤其是mysql数据库采用master-slave和shards技术实现了mysql数据库的负载均衡,解决了数据库的瓶颈,达到了数据库横向扩展的目标。

3、YouTube架构总结

这个貌似在国内是被和谐的,要fan qiang才能访问(不知到底何故)。看看他的架构
–NetScaler用于负载均衡和静态内容缓存
–使用lighttpd作为Web服务器来提供视频服务
–CDN在多个地方备份内容,这样内容离用户更近的机会就会更高
–使用Google的BigTable,一个分布式数据存储、数据库分成shards,不同的用户指定到不同的shards、使用BigTable将图片备份到不同的数据中心,代码查看谁是最近的

4、PlentyOfFish架构总结

这个我觉的最神奇了,一个人每天花2个小时,可以维护一个每天3000W PV的,而且是基于.NET的(呵呵,终于给我们.net程序员一个好榜样了)。简述他的架构
–用Microsoft Windows操作系统作为服务器

–使用ASP.NET技术

–使用IIS作为Web容器

–用Akamai CDN来缓存网页

–用Foundry ServerIron 来做负载均衡

–sqlserver采用master-slave架构,两台负责read操作,master那台负责写操作

–所有的request数据都使用了gzip压缩

5、WikiPedia架构总结

维基百科(Wikipedia)是一个基于Wiki技术的全球性多语言百科全书协作计划,同时也是一部在网际网路上呈现的网路百科全书,其目标及宗旨是为全人类提供自由的百科全书——用他们所选择的语言来书写而成的,是一个动态的、可自由和的全球知识体。

–GeoDNS让用户能够访问离他地域最近的Web服务器

–用LVS实现负载均衡

–用Lighttpd做图片服务器

–使用MediaWiki软件

–大量缓存(Cache),Squid作为反向代理,Memcached做数据缓存

–用Mysql数据库集群

6、Google架构

Google的架构大概地整理一下:

–GFS,Google的强有力的面向大规模数据密集型应用的、可伸缩的分布式文件系统

–MapReduce,Google的分布式并行计算系统,GFS存储数据,而MapReduce则是以最快最可靠的方式处理数据。

–BigTable,Google基于GFS和MapReduce之上的用来存储结构化数据的解决方案,有了它,不仅可以存储结构化的数据,而且可以更好的管理和做出负载均衡决策。

7、优酷网架构

在国内,上不了YouTube,只能看看优酷了,说实在优酷在国内算是做的不错了,视频加载速度明显比土豆什么的要快,那就看看他的架构吧:

–自建的一个模块化的CMS系统,前端十分灵活

–mysql数据库从单台MySQL服务器(Just Running)到简单的MySQL主从复制、SSD优化、垂直分库、水平sharding分库,解决数据库服务器的灵活横向扩展。

–为了避免内存拷贝和内存锁,没有(很少)用内容缓存。

–最核心的是构建了比较完善的CDN网络,就近原则,让你看视频时从离你最近的服务器上获取视频信息,所以我们看优酷比土豆要快,原因就在这里。

8、Twitter架构

twitter,怎么说呢,说他简单么还真简单,但又是那么复杂,真是纠结。话说这140个字的鼻祖让国内的某某某非常风骚,算了不跑题了,说说他的架构吧:

–平台比较广泛:

-Ruby on Rails:web应用程序的框架
-Erlang:通用的面向并发的编程语言,开源项目地址:http://www.erlang.org/
-AWStats:实时日志分析系统:开源项目地址:http://awstats.sourceforge.net/
-Memcached:分布式内存缓存组建
-Starling:Ruby开发的轻量级消息队列
-Varnish:高性能开源HTTP加速器
-Kestrel:scala编写的消息中间件,开源项目地址:http://github.com/robey/kestrel
-Comet Server:Comet是一种ajax长连接技术,利用Comet可以实现服务器主动向web浏览器推送数据,从而避免客户端的轮询带来的性能损失。
-libmemcached:一个memcached客户端
-使用mysql数据库服务器
-Mongrel:Ruby的http服务器,专门应用于rails,开源项目地址:http://rubyforge.org/projects/mongrel/
-Munin:服务端监控程序,项目地址:http://munin-monitoring.org/
-Nagios:网络监控系统,项目地址:http://www.nagios.org/
–细化memcached,同时建立向量缓存Vector Cache、行缓存Row Cache、碎片缓存Fragmeng Cache、缓存池Page Cache
–给力的消息队列,用Ruby写的一个分布式队列 Starling

9、Yupoo网站架构

一个试图做国内最好的图片服务提供商,虽然和Flickr还有点差距,但也不错了,话说搞图片和视频的是很烧服务器和带宽的,在国内这么贵的带宽也挺不容易的,好了,一起看看他的架构吧:

–Squid,这个貌似做图片缓存挺好使的,而且还是分布式的,可以硬盘命中和内存命中,速度都还不错。

–MogileFS图片存储

–mysql分库设计,垂直分库,水平sharding,跨库关联查询

–透明的缓存设计

10、Amazon网站架构

这个Amazon从小书店开始现在成了全球商品品种最多的网上零售商和全球第2大互联网公司,貌似很风光嘛,那架构一定很犀利的,下面一起来看看:

–平台,Linux、oracle、C++、Perl、Mason、Java、Jboss、Servlets

–Dynamo Key-Value存储架构

10种排序算法总结

排序算法有很多,所以在特定情景中使用哪一种算法很重要。为了选择合适的算法,可以按照建议的顺序考虑以下标准:
(1)执行时间
(2)存储空间
(3)编程工作
对于数据量较小的情形,(1)(2)差别不大,主要考虑(3);而对于数据量大的,(1)为首要。

主要排序法有:
一、冒泡(Bubble)排序——相邻交换
二、选择排序——每次最小/大排在相应的位置
三、插入排序——将下一个插入已排好的序列中
四、壳(Shell)排序——缩小增量
五、归并排序
六、快速排序
七、堆排序
八、拓扑排序
九、锦标赛排序
十、基数排序

一、冒泡(Bubble)排序

———————————-Code 从小到大排序n个数————————————
void BubbleSortArray()
{
for(int i=1;i<>
{
for(int j=0;i<>
{
if(a[j]>a[j+1])//比较交换相邻元素
{
int temp;
temp=a[j]; a[j]=a[j+1]; a[j+1]=temp;
}
}
}
}
————————————————-Code————————————————
效率 O(n²),适用于排序小列表。

二、选择排序
———————————-Code 从小到大排序n个数——————————–
void SelectSortArray()
{
int min_index;
for(int i=0;i<>
{
min_index=i;
for(int j=i+1;j
if(arr[j]
if(min_index!=i)//找到最小项交换,即将这一项移到列表中的正确位置
{
int temp;
temp=arr[i]; arr[i]=arr[min_index]; arr[min_index]=temp;
}
}
}
————————————————-Code—————————————–
效率O(n²),适用于排序小的列表。

三、插入排序
——————————————–Code 从小到大排序n个数————————————-
void InsertSortArray()
{
for(int i=1;i
{
int temp=arr[i];//temp标记为未排序第一个元素
int j=i-1;
while (j>=0 && arr[j]>temp)/*将temp与已排序元素从小到大比较,寻找temp应插入的位置*/
{
arr[j+1]=arr[j];
j–;
}
arr[j+1]=temp;
}
}
——————————Code————————————————————–
最佳效率O(n);最糟效率O(n²)与冒泡、选择相同,适用于排序小列表
若列表基本有序,则插入排序比冒泡、选择更有效率。

四、壳(Shell)排序——缩小增量排序
————————————-Code 从小到大排序n个数————————————-
void ShellSortArray()
{
for(int incr=3;incr<0;incr–)//增量递减,以增量3,2,1为例
{
for(int L=0;L<(n-1)/incr;L++)//重复分成的每个子列表
{
for(int i=L+incr;i
{
int temp=arr[i];
int j=i-incr;
while(j>=0&&arr[j]>temp)
{
arr[j+incr]=arr[j];
j-=incr;
}
arr[j+incr]=temp;
}
}
}
}
————————————–Code——————————————-
适用于排序小列表。
效率估计O(nlog2^n)~O(n^1.5),取决于增量值的最初大小。建议使用质数作为增量值,因为如果增量值是2的幂,则在下一个通道中会再次比较相同的元素。
壳(Shell)排序改进了插入排序,减少了比较的次数。是不稳定的排序,因为排序过程中元素可能会前后跳跃。

五、归并排序
———————————————-Code 从小到大排序—————————————
void MergeSort(int low,int high)
{
if(low>=high)   return;//每个子列表中剩下一个元素时停止
else int mid=(low+high)/2;/*将列表划分成相等的两个子列表,若有奇数个元素,则在左边子列表大于右侧子列表*/
MergeSort(low,mid);//子列表进一步划分
MergeSort(mid+1,high);
int [] B=new int [high-low+1];//新建一个数组,用于存放归并的元素
for(int i=low,j=mid+1,k=low;i<=mid && j<=high;k++)/*两个子列表进行排序归并,直到两个子列表中的一个结束*/
{
if (arr[i]<=arr[j];)
{
B[k]=arr[i];
I++;
}
else
{ B[k]=arr[j]; j++; }
}
for(   ;j<=high;j++,k++)//如果第二个子列表中仍然有元素,则追加到新列表
B[k]=arr[j];
for(   ;i<=mid;i++,k++)//如果在第一个子列表中仍然有元素,则追加到新列表中
B[k]=arr[i];
for(int z=0;z
arr[z]=B[z];
}
—————————————————–Code—————————————————
效率O(nlogn),归并的最佳、平均和最糟用例效率之间没有差异。
适用于排序大列表,基于分治法。

六、快速排序
————————————Code——————————————–
/*快速排序的算法思想:选定一个枢纽元素,对待排序序列进行分割,分割之后的序列一个部分小于枢纽元素,一个部分大于枢纽元素,再对这两个分割好的子序列进行上述的过程。*/                  void swap(int a,int b){int t;t =a ;a =b ;b =t ;}
int Partition(int [] arr,int low,int high)
{
int pivot=arr[low];//采用子序列的第一个元素作为枢纽元素
while (low < high)
{
//从后往前栽后半部分中寻找第一个小于枢纽元素的元素
while (low < high && arr[high] >= pivot)
{
–high;
}
//将这个比枢纽元素小的元素交换到前半部分
swap(arr[low], arr[high]);
//从前往后在前半部分中寻找第一个大于枢纽元素的元素
while (low
{
++low ;
}
swap (arr [low ],arr [high ]);//将这个枢纽元素大的元素交换到后半部分
}
return low ;//返回枢纽元素所在的位置
}
void QuickSort(int [] a,int low,int high)
{
if (low
{
int n=Partition (a ,low ,high );
QuickSort (a ,low ,n );
QuickSort (a ,n +1,high );
}
}
—————————————-Code————————————-
平均效率O(nlogn),适用于排序大列表。
此算法的总时间取决于枢纽值的位置;选择第一个元素作为枢纽,可能导致O(n²)的最糟用例效率。若数基本有序,效率反而最差。选项中间值作为枢纽,效率是O(nlogn)。
基于分治法。

七、堆排序
最大堆:后者任一非终端节点的关键字均大于或等于它的左、右孩子的关键字,此时位于堆顶的节点的关键字是整个序列中最大的。
思想:
(1)令i=l,并令temp= kl ;
(2)计算i的左孩子j=2i+1;
(3)若j<=n-1,则转(4),否则转(6);
(4)比较kj和kj+1,若kj+1>kj,则令j=j+1,否则j不变;
(5)比较temp和kj,若kj>temp,则令ki等于kj,并令i=j,j=2i+1,并转(3),否则转(6)
(6)令ki等于temp,结束。
—————————————–Code—————————
void HeapSort(SeqIAst R)

{ //对R[1..n]进行堆排序,不妨用R[0]做暂存单元    int I;    BuildHeap(R); //将R[1-n]建成初始堆for(i=n;i>1;i–) //对当前无序区R[1..i]进行堆排序,共做n-1趟。{      R[0]=R[1]; R[1]=R[i]; R[i]=R[0]; //将堆顶和堆中最后一个记录交换      Heapify(R,1,i-1);  //将R[1..i-1]重新调整为堆,仅有R[1]可能违反堆性质     }    } —————————————Code————————————–

堆排序的时间,主要由建立初始堆和反复重建堆这两部分的时间开销构成,它们均是通过调用Heapify实现的。

堆排序的最坏时间复杂度为O(nlgn)。堆排序的平均性能较接近于最坏性能。     由于建初始堆所需的比较次数较多,所以堆排序不适宜于记录数较少的文件。     堆排序是就地排序,辅助空间为O(1),     它是不稳定的排序方法。

堆排序与直接插入排序的区别:
直接选择排序中,为了从R[1..n]中选出关键字最小的记录,必须进行n-1次比较,然后在R[2..n]中选出关键字最小的记录,又需要做n-2次比较。事实上,后面的n-2次比较中,有许多比较可能在前面的n-1次比较中已经做过,但由于前一趟排序时未保留这些比较结果,所以后一趟排序时又重复执行了这些比较操作。
堆排序可通过树形结构保存部分比较结果,可减少比较次数。

八、拓扑排序
例 :学生选修课排课先后顺序
拓扑排序:把有向图中各顶点按照它们相互之间的优先关系排列成一个线性序列的过程。
方法:
在有向图中选一个没有前驱的顶点且输出
从图中删除该顶点和所有以它为尾的弧
重复上述两步,直至全部顶点均已输出(拓扑排序成功),或者当图中不存在无前驱的顶点(图中有回路)为止。
—————————————Code————————————–
void TopologicalSort()/*输出拓扑排序函数。若G无回路,则输出G的顶点的一个拓扑序列并返回OK,否则返回ERROR*/
{
int indegree[M];
int i,k,j;
char n;
int count=0;
Stack thestack;
FindInDegree(G,indegree);//对各顶点求入度indegree[0....num]
InitStack(thestack);//初始化栈
for(i=0;i<>
Console.WriteLine(“结点”+G.vertices[i].data+”的入度为”+indegree[i]);
for(i=0;i<>
{
if(indegree[i]==0)
Push(thestack.vertices[i]);
}
Console.Write(“拓扑排序输出顺序为:”);
while(thestack.Peek()!=null)
{
Pop(thestack.Peek());
j=locatevex(G,n);
if (j==-2)
{
Console.WriteLine(“发生错误,程序结束。”);
exit();
}
Console.Write(G.vertices[j].data);
count++;
for(p=G.vertices[j].firstarc;p!=NULL;p=p.nextarc)
{
k=p.adjvex;
if (!(–indegree[k]))
Push(G.vertices[k]);
}
}
if (count<>
Cosole.WriteLine(“该图有环,出现错误,无法排序。”);
else
Console.WriteLine(“排序成功。”);
}
—————————————-Code————————————–
算法的时间复杂度O(n+e)。

九、锦标赛排序
锦标赛排序的算法思想与体育比赛类似。
首先将n个数据元素两两分组,分别按关键字进行比较,得到n/2个比较的优胜者(关键字小者),作为第一步比较的结果保留下来,
然后对这n/2个数据元素再两两分组,分别按关键字进行比较,…,如此重复,直到选出一个关键字最小的数据元素为止。

——————————–Code in C—————————————
#include
#include
#include
#include
#define SIZE 100000
#define MAX 1000000
struct node
{
long num;//关键字
char str[10];
int lastwin;//最后胜的对手
int killer;//被击败的对手
long times;//比赛次数
}data[SIZE];
long CompareNum=0;
long ExchangeNum=0;
long Read(char name[])//读取文件a.txt中的数据,并存放在数组data[]中;最后返回数据的个数
{
FILE *fp;
long i=1;
fp=fopen(name,”rw”);
fscanf(fp,”%d%s”,&data[i].num,data[i].str);
while(!feof(fp))
{
i++;
fscanf(fp,”%d%s”,&data[i].num,data[i].str);
}
return (i-1);
}
long Create(long num)//创建胜者树,返回冠军(最小数)在数组data[]中的下标
{
int i,j1,j2,max,time=1;
long min;//记录当前冠军的下标
for(i=1;pow(2,i-1)<>
;
max=pow(2,i-1);//求叶子结点数目
for(i=1;i<=max;i++)//初始化叶子结点
{
data[i].killer=0;
data[i].lastwin=0;
data[i].times=0;
if(i>num)
data[i].num=MAX;
}
for(i=1;i<=max;i+=2)//第一轮比赛
{
++CompareNum;
if(data[i].num <= data[i+1].num)
{
data[i].lastwin = i+1;
data[i+1].killer=i;
++data[i].times;
++data[i+1].times;
min=i;
}
else
{
data[i+1].lastwin=i;
data[i].killer=i+1;
++data[i].times;
++data[i+1].times;
min=i+1;
}
}
j1=j2=0;//记录连续的两个未被淘汰的选手的下标
while(time <= (log(max)/log(2)))//进行淘汰赛
{
for(i=1;i<=max;i++)
{
if(data[i].times==time && data[i].killer==0)//找到一名选手
{
j2=i;//默认其为两选手中的后来的
if(j1==0)//如果第一位置是空的,则刚来的选手先来的
j1=j2;
else//否则刚来的选手是后来的,那么选手都已到场比赛开始
{
++CompareNum;
if(data[j1].num <= data[j2].num)//先来的选手获胜
{
data[j1].lastwin = j2;//最后赢的是j2
data[j2].killer=j1;//j2是被j1淘汰的
++data[j1].times;
++data[j2].times;//两选手场次均加1
min=j1;//最小数下标为j1
j1=j2=0;//将j1,j2置0
}
else//同理
{
data[j2].lastwin=j1;
data[j1].killer=j2;
++data[j1].times;
++data[j2].times;
min=j2;
j1=j2=0;
}
}
}

}
time++;//轮数加1
}
return min;//返回冠军的下标
}
void TournamentSort(long num)//锦标赛排序
{
long tag=Create(num);//返回最小数下标
FILE *fp1;
fp1=fopen(“sort.txt”,”w+”);//为写入创建并打开文件sort.txt
while(data[tag].num != MAX)//当最小值不是无穷大时
{
printf(“%d %s\n”,data[tag].num,data[tag].str);//输出数据
fprintf(fp1,”%d %s\n”,data[tag].num,data[tag].str);//写入数据
data[tag].num=MAX;//将当前冠军用无穷大替换
tag=Create(num);//返回下一个冠军的下标
}
}
int main()
{
int num;
char name[10];
printf(“Input name of the file:”);
gets(name);
num=Read(name);//读文件
TournamentSort(num);//锦标赛排序
printf(“CompareNum=%d\nExchangeNum=%d\n”,CompareNum,ExchangeNum);
return 0;
}
——————————————Code————————————-

十、基数排序
基数排序又被称为桶排序。与前面介绍的几种排序方法相比较,基数排序和它们有明显的不同。
前面所介绍的排序方法都是建立在对数据元素关键字进行比较的基础上,所以可以称为基于比较的排序;
而基数排序首先将待排序数据元素依次“分配”到不同的桶里,然后再把各桶中的数据元素“收集”到一起。
通过使用对多关键字进行排序的这种“分配”和“收集”的方法,基数排序实现了对多关键字进行排序。
———————————————————————————————————————
例:
每张扑克牌有两个“关键字”:花色和面值。其大小顺序为:
花色:§<¨<©<ª
面值:2<3<……<K<A
扑克牌的大小先根据花色比较,花色大的牌比花色小的牌大;花色一样的牌再根据面值比较大小。所以,将扑克牌按从小到大的次序排列,可得到以下序列:
§2,…,§A,¨2,…,¨A,©2,…,©A,ª2,…,ªA
这种排序相当于有两个关键字的排序,一般有两种方法实现。
其一:可以先按花色分成四堆(每一堆牌具有相同的花色),然后在每一堆牌里再按面值从小到大的次序排序,最后把已排好序的四堆牌按花色从小到大次序叠放在一起就得到排序的结果。
其二:可以先按面值排序分成十三堆(每一堆牌具有相同的面值),然后将这十三堆牌按面值从小到大的顺序叠放在一起,再把整副牌按顺序根据花色再分成四堆(每一堆牌已按面值从小到大的顺序有序),最后将这四堆牌按花色从小到大合在一起就得到排序的结果。
———————————————————————————————————————
实现方法:
最高位优先(Most Significant Digit first)法,简称MSD法:先按k1排序分组,同一组中记录,关键码k1相等,再对各组按k2排序分成子组,之后,对后面的关键码继续这样的排序分组,直到按最次位关键码kd对各子组排序后。再将各组连接起来,便得到一个有序序列。
最低位优先(Least Significant Digit first)法,简称LSD法:先从kd开始排序,再对kd-1进行排序,依次重复,直到对k1排序后便得到一个有序序列。
———————————Code in C#——————————————
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace LearnSort
{
class Program
{
static void Main(string[] args)
{
int[] arr = CreateRandomArray(10);//产生随机数组
Print(arr);//输出数组
RadixSort(ref arr);//排序
Print(arr);//输出排序后的结果
Console.ReadKey();
}
public static void RadixSort(ref int[] arr)
{
int iMaxLength = GetMaxLength(arr);
RadixSort(ref arr, iMaxLength);
}
private static void RadixSort(ref int[] arr, int iMaxLength)
{
List list = new List();//存放每次排序后的元素
List[] listArr = new List[10];//十个桶
char currnetChar;//存放当前的字符比如说某个元素123 中的2
string currentItem;//存放当前的元素比如说某个元素123
for (int i = 0; i < listArr.Length; i++)//给十个桶分配内存初始化。
listArr[i] = new List();
for (int i = 0; i < iMaxLength; i++)//一共执行iMaxLength次,iMaxLength是元素的最大位数。
{
foreach (int number in arr)//分桶
{
currentItem = number.ToString();//将当前元素转化成字符串
try { currnetChar = currentItem[currentItem.Length-i-1]; }//从个位向高位开始分桶
catch { listArr[0].Add(number); continue; }//如果发生异常,则将该数压入listArr[0]。比如说5 是没有十位数的,执行上面的操作肯定会发生越界异常的,这正是期望的行为,我们认为5的十位数是0,所以将它压入listArr[0]的桶里。
switch (currnetChar)//通过currnetChar的值,确定它压人哪个桶中。
{
case ’0′: listArr[0].Add(number); break;
case ’1′: listArr[1].Add(number); break;
case ’2′: listArr[2].Add(number); break;
case ’3′: listArr[3].Add(number); break;
case ’4′: listArr[4].Add(number); break;
case ’5′: listArr[5].Add(number); break;
case ’6′: listArr[6].Add(number); break;
case ’7′: listArr[7].Add(number); break;
case ’8′: listArr[8].Add(number); break;
case ’9′: listArr[9].Add(number); break;
default: throw new Exception(“unknow error”);
}
}
for (int j = 0; j < listArr.Length; j++)//将十个桶里的数据重新排列,压入list
foreach (int number in listArr[j].ToArray())
{
list.Add(number);
listArr[j].Clear();//清空每个桶
}
arr = list.ToArray();//arr指向重新排列的元素
//Console.Write(“{0} times:”,i);
Print(arr);//输出一次排列的结果
list.Clear();//清空list
}
}
//得到最大元素的位数
private static int GetMaxLength(int[] arr)
{
int iMaxNumber = Int32.MinValue;
foreach (int i in arr)//遍历得到最大值
{
if (i > iMaxNumber)
iMaxNumber = i;
}
return iMaxNumber.ToString().Length;//这样获得最大元素的位数是不是有点投机取巧了…
}
//输出数组元素
public static void Print(int[] arr)
{
foreach (int i in arr)
System.Console.Write(i.ToString()+’\t’);
System.Console.WriteLine();
}
//产生随机数组。随机数的范围是0到1000。参数iLength指产生多少个随机数
public static int[] CreateRandomArray(int iLength)
{
int[] arr = new int[iLength];
Random random = new Random();
for (int i = 0; i < iLength; i++)
arr[i] = random.Next(0,1001);
return arr;
}
}
}
———————————Code ———————————————
基数排序法是属于稳定性的排序,其时间复杂度为O (nlog(r)m),其中r为所采取的基数,而m为堆数,在某些时候,基数排序法的效率高于其它的比较性排序法。

c#的random shuffle(生成不重复的随机数)

前段时间在C#里需要用到random shuffle功能,一时没找到合适的代码,就按自己的理解写了一段,所得到结果也能满足自己的需要。值得注意的一点是随机数生成器的选择。直接以Random做为随机数生成器因为时钟精度问题,在一个小的时间段内会得到同样的伪随机数序列,您shuffle后会得到同一个结果。.net提供了RNGCryptoServiceProvider能够避免这种情况,下面是几种用法的示例

1 ///


2 /// RandomShuffle
3 /// WuErPing 2006/12/07
4 ///

5 public sealed class RandomShuffle
6 {
7 private RandomShuffle() { }
8
9 // pseudo-random number generator, using a time-dependent default seed value.
10 static public List Shuffle(int size)
11 {
12 List list = new List(size);
13 for (int i = 0; i < size; i)
14 {
15 list.Insert(i, i);
16 }
17 System.Random random = new Random();
18 for (int i = 0; i < list.Count; i)
19 {
20 int var = random.Next(0, list.Count);
21 int temp = list[i];
22 list[i] = list[var];
23 list[var] = temp;
24 }
25
26 return list;
27 }
28
29 // using a RNGCryptoServiceProvider().GetHashCode() seed value
30 static public List ShuffleEx(int size)
31 {
32 List list = new List(size);
33 for (int i = 0; i < size; i)
34 {
35 list.Insert(i, i);
36 }
37 System.Random random = new Random(new RNGCryptoServiceProvider().GetHashCode());
38 for (int i = 0; i < list.Count; i)
39 {
40 int var = random.Next(0, list.Count);
41 int temp = list[i];
42 list[i] = list[var];
43 list[var] = temp;
44 }
45
46 return list;
47 }
48
49 // Cryptographic random number generators create cryptographically strong random values
50 static public List ShufflePro(int size)
51 {
52 List list = new List(size);
53 for (int i = 0; i < size; i)
54 {
55 list.Insert(i, i);
56 }
57 byte[] randomBytes = new Byte[4];
58 RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
59 for (int i = 0; i < list.Count; i)
60 {
61 rng.GetNonZeroBytes(randomBytes);
62 int randomSeed = (randomBytes[0] << 24) | (randomBytes[1] << 16) | (randomBytes[2] << 8) | randomBytes[3];
63 int var = randomSeed % list.Count;
64 //var = System.Math.Abs(var);
65 if (var < 0) var *= -1;
66 int temp = list[i];
67 list[i] = list[var];
68 list[var] = temp;
69 }
70 return list;
71 }
72 }
注:假如要深究random shuffle算法,能够看标准C++的random_shuffle的实现。根据SGI的文档http://www.sgi.com/tech/stl/random_shuffle.html,算法来自
[1] This algorithm is described in section 3.4.2 of Knuth (D. E. Knuth, The Art of Computer Programming. Volume 2: Seminumerical Algorithms, second edition. Addison-Wesley, 1981). Knuth credits Moses and Oakford (1963) and Durstenfeld (1964).

附:vc8的random_shuffle的实现

1 // TEMPLATE FUNCTION random_shuffle
2 template
3 class _Diff> inline
4 void _Random_shuffle(_RanIt _First, _RanIt _Last, _Diff *)
5 { // shuffle [_First, _Last)
6 _DEBUG_RANGE(_First, _Last);
7 const int _RANDOM_BITS = 15; // minimum random bits from rand()
8 const int _RANDOM_MAX = (1U << _RANDOM_BITS) – 1;
9
10 _RanIt _Next = _First;
11 for (unsigned long _Index = 2; _Next != _Last; _Index)
12 { // assume unsigned long big enough for _Diff count
13 unsigned long _Rm = _RANDOM_MAX;
14 unsigned long _Rn = ::rand() & _RANDOM_MAX;
15 for (; _Rm < _Index && _Rm != ~0UL;
16 _Rm = _Rm << _RANDOM_BITS | _RANDOM_MAX)
17 _Rn = _Rn << _RANDOM_BITS
18 | (::rand() & _RANDOM_MAX); // build random value
19
20 std::iter_swap(_Next, _First _Diff(_Rn % _Index)); // swap a pair
21 }
22 }
23

http://www.cnblogs.com/WuErPIng/archive/2006/12/31/609224.html

 

 

版权申明:本站文章均来自网络,如有侵权,请联系028-86262244-215 ,我们收到后立即删除,谢谢!
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有。

c#中使用net share命令时要注意的问题

最近的这个项目中有一需要就是要将数据放在局域网上共享,使其他机器来访问。这样就必须要将文档夹共享,本来是考虑用API来实现共享,但是后发现太繁琐,所以采用了NET SHARE这条WINDOWS命令。

System.Diagnostics.Process p = new System.Diagnostics.Process();
p.StartInfo.FileName = “cmd”;
p.StartInfo.Arguments = ” /c net share ” shareName “=” sharePath;
p.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
p.StartInfo.CreateNoWindow = true;
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.Start();

p.WaitForExit();
shareName:能够是任何有效的共享名。sharePath:是要共享的完整路径。
项目制作过程没有发现任何不对,但到了安装到program files目录下就出现问题了,不能正确的共享,排查发现是路径中有空格的原因。在网上找了一些文章,解决办法是加上引号即可:

p.StartInfo.Arguments = ” /c net share ” shareName “=\”" sharePath “\”";

http://www.cnblogs.com/wanlang/archive/2006/11/22/568705.html

snowflake snowflake snowflake snowflake snowflake snowflake snowflake snowflake snowflake snowflake snowflake snowflake snowflake snowflake snowflake snowflake snowflake snowflake snowflake snowflakeWordpress balloons powered by nksnow