What is ‘if __name__ == “__main__”‘ for?[转]

10月 10th, 2008

The if __name__ == "__main__": ... trick exists in Python so that our Python files can act as either reusable modules, or as standalone programs. As a toy example, let’s say that we have two files:

$ cat mymath.py
def square(x):
    return x * x

if __name__ == '__main__':
    print "test: square(42) ==", square(42)

$ cat mygame.py
import mymath

print "this is mygame."
print mymath.square(17)

In this example, we’ve written mymath.py to be both used as a utility module, as well as a standalone program. We can run mymath standalone by doing this:

$ python mymath.py
test: square(42) == 1764

But we can also use mymath.py as a module; let’s see what happens when we run mygame.py:

$ python mygame.py
this is mygame.
289

Notice that here we don’t see the ‘test’ line that mymath.py had near the bottom of its code. That’s because, in this context, mymath is not the main program. That’s what the if __name__ == "__main__": ... trick is used for.

[From a post to Python Tutor by Danny Yoo]

memcached的分布式算法-Consistent Hashing[转]

10月 7th, 2008

前言:

我们知道以往资料要放到 M 台服务器上,最简单的方法就是取余数 (hash_value % M) 然后放到对应的服务器上,那就是当添加或移除服务器时,缓存重组的代价相当巨大。 添加服务器后,余数就会产生巨变,这样就无法获取与保存时相同的服务器, 从而影响缓存的命中率。

下面这篇文章写的非常好,结合memcached的 特点利用Consistent hasning 算法,可以打造一个非常完备的分布式缓存服务器。

我是Mixi的长野。 本次不再介绍memcached的内部结构, 开始介绍memcached的分布式。

 

memcached的分布式

正如第1次中介绍的那样, memcached虽然称为“分布式”缓存服务器,但服务器端并没有“分布式”功能。 服务器端仅包括 第2次、 第3次 前坂介绍的内存存储功能,其实现非常简单。 至于memcached的分布式,则是完全由客户端程序库实现的。 这种分布式是memcached的最大特点。

memcached的分布式是什么意思?

这里多次使用了“分布式”这个词,但并未做详细解释。 现在开始简单地介绍一下其原理,各个客户端的实现基本相同。

下面假设memcached服务器有node1~node3三台, 应用程序要保存键名为“tokyo”“kanagawa”“chiba”“saitama”“gunma” 的数据。

memcached-0004-01.png

图1 分布式简介:准备

首先向memcached中添加“tokyo”。将“tokyo”传给客户端程序库后, 客户端实现的算法就会根据“键”来决定保存数据的memcached服务器。 服务器选定后,即命令它保存“tokyo”及其值。

memcached-0004-02.png

图2 分布式简介:添加时

同样,“kanagawa”“chiba”“saitama”“gunma”都是先选择服务器再保存。

接下来获取保存的数据。获取时也要将要获取的键“tokyo”传递给函数库。 函数库通过与数据保存时相同的算法,根据“键”选择服务器。 使用的算法相同,就能选中与保存时相同的服务器,然后发送get命令。 只要数据没有因为某些原因被删除,就能获得保存的值。

memcached-0004-03.png

图3 分布式简介:获取时

这样,将不同的键保存到不同的服务器上,就实现了memcached的分布式。 memcached服务器增多后,键就会分散,即使一台memcached服务器发生故障 无法连接,也不会影响其他的缓存,系统依然能继续运行。

接下来介绍第1次 中提到的Perl客户端函数库Cache::Memcached实现的分布式方法。

Cache::Memcached的分布式方法

Perl的memcached客户端函数库Cache::Memcached是 memcached的作者Brad Fitzpatrick的作品,可以说是原装的函数库了。

该函数库实现了分布式功能,是memcached标准的分布式方法。

根据余数计算分散

Cache::Memcached的分布式方法简单来说,就是“根据服务器台数的余数进行分散”。 求得键的整数哈希值,再除以服务器台数,根据其余数来选择服务器。

下面将Cache::Memcached简化成以下的Perl脚本来进行说明。

use strict;
use warnings;
use String::CRC32;

my @nodes = (’node1′,’node2′,’node3′);
my @keys = (’tokyo’, ‘kanagawa’, ‘chiba’, ’saitama’, ‘gunma’);

foreach my $key (@keys) {
my $crc = crc32($key); # CRC値
my $mod = $crc % ( $#nodes + 1 );
my $server = $nodes[ $mod ]; # 根据余数选择服务器
printf “%s => %s\n”, $key, $server;
}
Cache::Memcached在求哈希值时使用了CRC。

首先求得字符串的CRC值,根据该值除以服务器节点数目得到的余数决定服务器。 上面的代码执行后输入以下结果:

tokyo       => node2
kanagawa => node3
chiba       => node2
saitama   => node1
gunma     => node1

根据该结果,“tokyo”分散到node2,“kanagawa”分散到node3等。 多说一句,当选择的服务器无法连接时,Cache::Memcached会将连接次数 添加到键之后,再次计算哈希值并尝试连接。这个动作称为rehash。 不希望rehash时可以在生成Cache::Memcached对象时指定“rehash => 0”选项。

根据余数计算分散的缺点

余数计算的方法简单,数据的分散性也相当优秀,但也有其缺点。 那就是当添加或移除服务器时,缓存重组的代价相当巨大。 添加服务器后,余数就会产生巨变,这样就无法获取与保存时相同的服务器, 从而影响缓存的命中率。用Perl写段代码来验证其代价。

use strict;
use warnings;
use String::CRC32;

my @nodes = @ARGV;
my @keys = (’a’..’z’);
my %nodes;

foreach my $key ( @keys ) {
my $hash = crc32($key);
my $mod = $hash % ( $#nodes + 1 );
my $server = $nodes[ $mod ];
push @{ $nodes{ $server } }, $key;
}

foreach my $node ( sort keys %nodes ) {
printf “%s: %s\n”, $node, join “,”, @{ $nodes{$node} };
}
这段Perl脚本演示了将“a”到“z”的键保存到memcached并访问的情况。 将其保存为mod.pl并执行。

首先,当服务器只有三台时:

$ mod.pl node1 node2 nod3
node1: a,c,d,e,h,j,n,u,w,x
node2: g,i,k,l,p,r,s,y
node3: b,f,m,o,q,t,v,z

结果如上,node1保存a、c、d、e……,node2保存g、i、k……, 每台服务器都保存了8个到10个数据。

接下来增加一台memcached服务器。

$ mod.pl node1 node2 node3 node4
node1: d,f,m,o,t,v
node2: b,i,k,p,r,y
node3: e,g,l,n,u,w
node4: a,c,h,j,q,s,x,z

添加了node4。可见,只有d、i、k、p、r、y命中了。像这样,添加节点后 键分散到的服务器会发生巨大变化。26个键中只有六个在访问原来的服务器, 其他的全都移到了其他服务器。命中率降低到23%。在Web应用程序中使用memcached时, 在添加memcached服务器的瞬间缓存效率会大幅度下降,负载会集中到数据库服务器上, 有可能会发生无法提供正常服务的情况。

mixi的Web应用程序运用中也有这个问题,导致无法添加memcached服务器。 但由于使用了新的分布式方法,现在可以轻而易举地添加memcached服务器了。 这种分布式方法称为 Consistent Hashing。

Consistent Hashing

关于Consistent Hashing的思想,mixi株式会社的开发blog等许多地方都介绍过, 这里只简单地说明一下。

Consistent Hashing的简单说明

Consistent Hashing如下所示:首先求出memcached服务器(节点)的哈希值, 并将其配置到0~232的圆(continuum)上。 然后用同样的方法求出存储数据的键的哈希值,并映射到圆上。 然后从数据映射到的位置开始顺时针查找,将数据保存到找到的第一个服务器上。 如果超过232仍然找不到服务器,就会保存到第一台memcached服务器上。

memcached-0004-04.png

图4 Consistent Hashing:基本原理

从上图的状态中添加一台memcached服务器。余数分布式算法由于保存键的服务器会发生巨大变化 而影响缓存的命中率,但Consistent Hashing中,只有在continuum上增加服务器的地点逆时针方向的 第一台服务器上的键会受到影响。

memcached-0004-05.png

图5 Consistent Hashing:添加服务器

因此,Consistent Hashing最大限度地抑制了键的重新分布。 而且,有的Consistent Hashing的实现方法还采用了虚拟节点的思想。 使用一般的hash函数的话,服务器的映射地点的分布非常不均匀。 因此,使用虚拟节点的思想,为每个物理节点(服务器) 在continuum上分配100~200个点。这样就能抑制分布不均匀, 最大限度地减小服务器增减时的缓存重新分布。

通过下文中介绍的使用Consistent Hashing算法的memcached客户端函数库进行测试的结果是, 由服务器台数(n)和增加的服务器台数(m)计算增加服务器后的命中率计算公式如下:

(1 - n/(n+m)) * 100

支持Consistent Hashing的函数库

本连载中多次介绍的Cache::Memcached虽然不支持Consistent Hashing, 但已有几个客户端函数库支持了这种新的分布式算法。 第一个支持Consistent Hashing和虚拟节点的memcached客户端函数库是 名为libketama的PHP库,由last.fm开发。

至于Perl客户端,连载的第1次 中介绍过的Cache::Memcached::Fast和Cache::Memcached::libmemcached支持 Consistent Hashing。

两者的接口都与Cache::Memcached几乎相同,如果正在使用Cache::Memcached, 那么就可以方便地替换过来。Cache::Memcached::Fast重新实现了libketama, 使用Consistent Hashing创建对象时可以指定ketama_points选项。

my $memcached = Cache::Memcached::Fast->new({
    servers => ["192.168.0.1:11211","192.168.0.2:11211"],
    ketama_points => 150
});

另外,Cache::Memcached::libmemcached 是一个使用了Brain Aker开发的C函数库libmemcached的Perl模块。 libmemcached本身支持几种分布式算法,也支持Consistent Hashing, 其Perl绑定也支持Consistent Hashing。

总结

本次介绍了memcached的分布式算法,主要有memcached的分布式是由客户端函数库实现, 以及高效率地分散数据的Consistent Hashing算法。下次将介绍mixi在memcached应用方面的一些经验, 和相关的兼容应用程序。

来源:http://www.paitoubing.cn/blog/memcached_consistent_hashing

你现在的真正年龄是多少

10月 5th, 2008

中国人的平均寿命是72岁,以此为基数,如果你现在是30岁,预期你真的活到72岁,那么你现在的标准年龄就是30;如果你不幸在40岁由于各种意外(在一般商业保险规定的赔付范围内,希望能明白我的隐含意思哦)over了,那么你现在的标准年龄就是54岁;如果你有幸活到耄耋之年(90岁),那么你现在的标准年龄是23岁.

现在你明白我的意思了吗,其实我们现在的标准年龄决定在未来的某个点.人现在的年龄只是个生理数值.并不代表什么.同样的30岁,有的人实际上很年轻.

更进一步,我想说,在某种意义上,我们都在同一起跑线上,机遇对于大家都是平等的.有时候我们觉得自己老了是因为受周围人的影响,太在意世俗人的眼光.俗话说,走自己的夜路,让别人说去吧,反正看不见,曲解黑夜路人的意思了,哈哈.

以上是我个人的突发奇想,呵呵.以下才是科学的计算寿命的方法,有兴趣的可以算算:

目前,中国人的平均寿命为72岁,以此为基数,回答下列问题,进行加减,最后就可得出您可能的寿命。

1.如果您是男性,减3岁;女性则加1岁。

2.居住在100万人以上的城市市区,减2岁;居住在人口少于1万人的小镇或农村,加2岁。

3.祖父母或外祖父母中有1位活到85岁,加2岁;4位祖辈都活到80岁,加6岁。

4.父母有1人在50岁明医以前死于中风或心脏病,减4岁;父母、兄弟姐妹中任何一位50岁前得癌症或心脏不正常,或自幼就有糖尿病,减3岁。

5.如果您是一位富翁,减2岁。

6.如果您大学毕业,加1岁;65岁仍在工作,加3岁。

7.如果您有配偶并住在一起,加5岁;如果没有,从25岁起每独居10年,减1岁。

8.如果您常伏案工作,减3岁;如果您常从事体力劳动,加3岁。

9.如果您每星期进行球类、游泳、跑步等运动5次,加4岁;每星期2次,加2岁。

10.如果您每晚睡眠超过10小时,减4岁。

11.经常紧张、易怒、性急,减3岁;感到生活很轻松,工作应付自如,加3岁。

12.如果您常常感到快乐,加1岁;经常感到不快,减2岁。

13.如果您去年因一次交通违章受罚,减1岁。

14.如果您抽烟,每天2包,减8岁;每天1-2包,减6岁;1包以下,减3岁。

15.如果您每天喝白酒50—100毫升,减1岁。

16.体重超过标准5公斤以上,减2岁;超过15公斤以上,减4岁;超过25公斤,减8岁。

17.如果您已40多岁,每年体检1次,加2岁;40岁以上女性,每年看妇科5次,加2岁。

18.如果您今年30—40岁,加3岁;40—50岁,加5岁;超过70岁,加6岁。

新世纪殖民经济

09月 27th, 2008

今天偶然看到一条新闻,让我触目惊心.以下我是节选的2段:

ADM益海集团,邦吉、嘉吉、路易达孚在拥有大豆供给的控制力后,这些跨国粮商开始寻找稳定、庞大的消费市场,以获得产业链延伸带来的巨大利润。

  他们看中的是中国。据了解,中国是世界最大的大豆进口国,每年进口大豆数量占全世界大豆贸易量的1/3以上。

  为推动外资粮商在中国的大豆业务,在外资粮商进入中国市场早期,美国大豆协会还专门来到中国为其运作。“采取的主要办法是做培训,介绍进口大豆的优势。”上述业内人士说。

  除了直接推广外,外资粮商还采取参股国内大豆压榨企业的方式,以期待在中国输出更多。

  益海集团在河南周口参股了一家大豆压榨企业。周口市委一位负责人告诉记者,早期该企业采用河南本地大豆,而后益海方面以本地大豆含油量不高为由,全面改用进口大豆为原料。

  “外资粮商的参股行为,就是为了让参股企业购买进口大豆,以稳定他们对中国的出口,他们并不关心产品的终端价格和参股企业的利润。”九三油脂有限责任公司(下称九三油脂)一直没有被外资染指,其总经理田仁礼曾这样分析。

  据了解,在全国大型的97家油脂企业中,64家被外资控制,比例高达66%。随之而来的是,1996年,中国已经变成了大豆净进口国,到了2007年,中国大豆净进口数量为3036万吨,是1996年的10倍,是2000年的3倍。

  通过参股方式,中国大豆的进口依存度日渐高涨。2008年6月,出访美国的中国商务代表团签署的采购协议显示,中国采购美国大豆的价值总额高达30亿美元。国家粮油信息中心也预测,2008年度,中国大豆进口量将大幅增加至3300万吨,进口依存度将高达71%。

……

标志事件正是让国内大豆压榨企业记忆犹新的“2004年大豆危机”。

  据油料分析师陈丽娜介绍,2004年美国农业部率先调低大豆产量,导致芝加哥期货交易所大豆价格连续上涨,价格上涨近一倍多。与此同时,不少大豆加工企业集中采购美国大豆。后来,美国农业部又调高产量数据,国际基金紧跟着反手做空,大豆价格突然直线下落。于是,巨大的价格落差,一下子将众多中小企业逼向绝境。

  一般情况下,大豆压榨企业的资金大约有95%将用于原材料的采购。因此,大豆价格至为关键。田仁礼对此曾断言,外资粮商所拥有的国家大豆价格的定价权正是其拥有的整合中国市场的能力的关键因素。他们打垮竞争对手、垄断市场的最佳武器,也正是这个定价权。

  在“2004年大豆危机”之后,国内压榨企业损失惨重,有近70%企业停产,大量企业倒闭。由于绝大部分国内压榨企业都需要向四大粮商采购大豆,因此,“2004年大豆危机”之后,不少企业都有相当规模的负债。

      看了大家都明白了.有句名言:手中有粮,心中不慌.粮食是国民的命脉,是工业的基础.跨国集团利用一只看不见的手控制了国民的饭碗.国家一定要注意.某些地方为了眼前的经济利益,不顾大局,无计划的引进外资进入粮食购销体系,最终损害的是国家,地方的利益.国家一定要警惕啊!

来源:http://news.sohu.com/20080927/n259774444.shtml

[原创]mogilefs 最新版本安装

09月 18th, 2008

一.介绍
首先可以去看官方的wiki:http://mogilefs.pbwiki.com/。(有可能被GFW了,那么你就安装一个Firefox的gladder插件就可以看了)。偶简单记录一下对Mogilefs的理解,Mogilefs分为几部分。
0) 数据库(MySQL)部分
你可以用mogdbsetup程序来初始化数据库。数据库保存了Mogilefs的所有元数据,你可以单独拿数据库服务器来做,也可以跟其他程序跑在一起,数据库部分非常重要,类似邮件系统的认证中心那么重要,如果这儿挂了,那么整个Mogilefs将处于不可用状态。因此最好是HA结构。
1)存储节点
mogstored程序的启动将使本机成为一个存储节点。启动时默认去读/etc/mogilefs/mogstored.conf ,具体配置可以参考配置部分。mogstored启动后,便可以通过mogadm增加这台机器到cluster中。一台机器可以只运行一个mogstored作为存储节点即可,也可以同时运行其他程序。
2)trackers(跟踪器)
mogilefsd即trackers程序,类似mogilefs的wiki上介绍的,trackers做了很多工作,Replication ,Deletion,Query,Reaper,Monitor等等。mogadm,mogtool的所有操作都要跟trackers打交道,Client的一些操作也需要定义好trackers,因此最好同时运行多个trackers来做负载均衡。trackers也可以只运行在一台机器上,也可以跟其他程序运行在一起,只要你配置好他的配置文件即可,默认在/etc/mogilefs/mogilefsd.conf。
3)工具
主要就是mogadm,mogtool这两个工具了,用来在命令行下控制整个mogilefs系统以及查看状态等等。
4)Client
Client实际上是一个Perl的pm,可以写程序调用该pm来使用mogilefs系统,对整个系统进行读写操作。

概念定义
可以参考官方wiki的这儿,简单说一下
domain:最高域,在一个域下key是唯一的。
class:包含在domain中,可以针对每一个class定义保存的份数。
key:对文件的唯一标识。
file:文件。

适用性
由于Mogilefs不支持对一个文件的随机读写,因此注定了只适合做一部分应用。比如图片服务,静态HTML服务。即文件写入后基本上不需要修改的应用,当然你也可以生成一个新的文件覆盖上去。

二.下载安装perl相关包

安装环境:
Red Hat Enterprise Linux AS release 4 (Nahant Update 6)
Linux 6.28 2.6.9-67.ELsmp #1 SMP Wed Nov 7 13:58:04 EST 2007 i686 i686 i386 GNU/Linux

注意:首先要安装mysql,mysql安装就不说了,网上不少,最好用源码包.

在cpan上下载以下包.搜索名字就可以找到

BSD-Resource-1.2901.tar.gz
Sys-Syscall-0.22.tar.gz

Time-HiRes-1.9715.tar.gz
Danga-Socket-1.57.tar.gz

Net-Netmask-1.9015.tar.gz
IO-AIO-3.07.tar.gz(Perl v5.8.8 required)
Perlbal-1.70

String-CRC32-1.4.tar.gz
Gearman-1.07.tar.gz
Gearman-Client-Async-0.93.tar.gz
Gearman-Server-1.08.tar.gz

DBI-1.607.tar.gz
DBD-mysql-4.008.tar.gz
PS:
ln -s /usr/local/mysql/lib/libmysqlclient.so.15 /usr/lib/libmysqlclient.so.15
perl Makefile.PL  –testhost=localhost –testuser=root –mysql_config=/usr/local/mysql/bin/mysql_config

(make test 有可能会有一个错误,不用管它)

IO-Compress-Base-2.015.tar.gz
IO-Compress-Zlib-2.015.tar.gz
Compress-Raw-Zlib-2.015.tar.gz
Compress-Zlib-2.015.tar.gz
IO-stringy-2.110.tar.gz

MogileFS-Client-1.08.tar.gz
mogilefs-server-2.20.tar.gz
MogileFS-Utils-2.13.tar.gz

PS:建议不是对PERL很熟悉,不要用SVN上的安装,不然会有莫名其妙的问题.

一定要按顺序安装,每个包解压缩,执行:
perl Makefile.PL
make
make test
make install

这样就安装成功了,注意make test的错误提示

三.配置

1)创建数据库
#mogdbsetup –dbhost=10.15.6.28 –dbname=mogilefs –dbuser=root

2)tracker配置
新建/etc/mogilefsd.conf文件内容:
db_dsn DBI:mysql:mogilefs
db_user mogile
db_pass 123123
conf_port 6001
listener_jobs 5
 
db_dsn指向的是你数据库的位置,如果你数据库不在同一个机器上,请改为:
db_dsn DBI:mysql:mogilefs:127.0.0.1
 
由于mogilefsd不能用root用户启动.所以添加mogile用户
# adduser mogile

在配置下面以前先启动 trackers server
# su mogile
# mogilefsd -c /etc/mogilefsd.conf –daemon

2)Storage Server 配置

用mogadm工具将storage server加到数据库中:
#mogadm -lib=/usr/lib/perl5/5.8.8 -trackers=10.15.6.28:6001 host add mogilestorage -ip=10.15.6.28 -port=7500 -status=alive(由于我是在一台机器上配,故trackers的地址和ip地址是一样的)

用下面命令来检测是否成功:
#mogadm -lib=/usr/lib/perl5/5.8.8 -trackers=10.15.6.28:6001 host list

加入一个设备到你的storage server:
#mogadm -lib=/usr/lib/perl5/5.8.8 -trackers=10.15.6.28:6001 device add mogilestorage 1

用下面命令来检测是否成功:
#mogadm -lib=/usr/lib/perl5/5.8.8 -trackers=10.15.6.28:6001 device list

Device ID 是唯一的,一旦创建将无法删除,只能mark为dead. 所以,如果你某个磁盘坏了,你mark为dead, 后来又修好了,
那么你必须重新格式化并命名为新的device id, 不支持将device从dead变为alive.
 
新建配置文件:/etc/mogstored.conf内容是
httplisten=0.0.0.0:7500
mgmtlisten=0.0.0.0:7501
docroot=/opt/mogdata

建个存放文件的目录 # mkdir /opt/mogdata
 
在存放文件的目录下面在建个目录:
#mkdir -p /opt/mogdata/dev1

PS:mogadm 参数的用法请参考http://search.cpan.org/~dormando/MogileFS-Utils/mogadm

3)运行MogileFS

启动 storage server
#mogstored -c /etc/mogstored.conf –daemon

启动 Trackers
su mogile
mogilefsd -c /etc/mogilefs/mogilefsd.conf –daemon

查看你所有的服务都起来没有
#ps -ef | grep mogilefsd
#ps -ef | grep mogstored

三.测试阶段
生成domain
#mogadm -lib=/usr/lib/perl5/5.8.8 -trackers=10.15.6.28:6001 domain add testdomain
 
加一个 class 到domain
#mogadm -lib=/usr/lib/perl5/5.8.8 -trackers=10.15.6.28:6001 class add testdomain testclass

写一个perl文件试一下test.pl
 
use MogileFS::Client;
my $mogfs = MogileFS::Client->new(domain=>’testdomain’, hosts=>['10.15.6.28:6001'], root=>’/opt/mogdata’,);
my $fh = $mogfs->new_file(”file_key”, “testclass”);
die $fh unless $fh->print($mogfs->readonly);
my $content = “file.txt”;
@num = $mogfs->store_content(”file_key”,”testclass”,$content);
print “@num \n”;
my $file_contents = $mogfs->get_file_data(”file_key”);
print “$file_contents \n”;
#$mogfs->delete(”file_key”);
$fh->print($file_contents);
@urls = $mogfs->get_paths(”file_key”);
print “@urls \n”;

返回的内容是
8
SCALAR(0×9ddaaa8)
http://10.15.6.28:7500/dev1/0/000/000/0000000008.fid

 

数据库测试代码:
#!/usr/bin/perl

# DBI is perl module used to connect to the database
use DBI;

# hostname or ip of server (for local testing, localhost should work)
$config{’dbServer’} = “localhost”;

# username and password to log onto db server
$config{’dbUser’} = “root”;
$config{’dbPass’} = “”;

# name of database
$config{’dbName’} = “test”;

# MySQL driver (shouldn’t need to change)
$config{’dataSource’} = “DBI:mysql:$config{’dbName’}:$config{’dbServer’}”;

my $dbh = DBI->connect($config{’dataSource’},$config{’dbUser’},$config{’dbPass’}) or
die “Can’t connect to $config{’dataSource’}<br>$DBI::errstr”;
 print “Connected successfully<br>”;
$dbh->disconnect();

谈spring的依赖注入[转]

09月 1st, 2008

当我第一次看到spring的时候就觉得似曾相识。这分明就是反射+配置文件+工厂模式。这样的框架是按照一些准则把设计模式打包成高层的模式。而spring技术中最闪耀的名词绝对少不了控制反转(IoC),依赖注入(D Injection)和依赖倒置(D Inversion)。

不管这些是方法论,还是模式,还是原则,有了这三样东西程序员的春天确实来了。不必再为了每一次的变化而心寒和纠结了。那么这又“反转”又“注入”又“依赖”的,到底是些什么东西呢?他们在干什么呢?不用行么?那么麻烦值得么?再有spring真的这么特别么,别的世界就没有spring么?

首先澄清下概念:“控制反转”,比方说本来你对某样事物有主动控制权,但是你却交了出去,那么你从主动控制转为被动,此即控制反转;“依赖注入”,一个实体依赖另一个实体,但在早期不体现这种依赖关系,而是把这种依赖关系提取出来,在后期注入回去;“依赖倒置”,以前高层依赖底层,但是底层变化后高层就没用了,后来不让高层依赖底层,让它依赖接口,这就是依赖的倒置,面向接口编程就是依赖倒置的灵魂。

以上是我用自己的话对几个概念的解释。不懂没关系,往下看。

先讲个实际生活的例子,假如某一天,您和您一哥们出去吃饭。坐到餐馆以后,您哥们说,“吃什么啊?”;你懒洋洋的说“随便”。

好,故事先就此打住。您这一随便不要紧啊,把吃什么的控制权交了出去啊,于是您和具体食物的关系算是没有了,因为您哥们说得算了。这就是控制反转,本来您可以决定吃米饭还是馒头,但是现在你只知道等下有东西吃但是吃什么你不知道了,因为控制具体吃什么的是您哥们。不过有一条,他一定会给你点能吃的,不能搞来一把锤子,虽然你把控制权交了出去,但是你还是有最基本的要求,能吃,此为一个接口。而后来不管上什么都要实现这个能吃的接口,此为依赖倒置或者说面向接口编程。

接下来,您哥们仔细想了半天,在点菜单上画了这个涂了那个,可他就是不说点了什么,最后给服务员去做了。等了若干分钟,上来两碗米饭,一个小鸡炖蘑菇,一个酸辣土豆丝。

到了此时您才看到他点了什么菜叫了什么饭,这就是依赖注入了。本来您和米饭和小鸡炖蘑菇是有依赖关系的,因为你要吃它们,但是在开始的时候却把你们隔离开,到了吃的时候你才看到它们。

下面我把伪类图画出来
春天不寒——谈spring的依赖注入
简单的写下代码:

Code
//约定的接口,和实现此接口的两个类。

interface Eatable{
    public void eat();
}

class Rice implements Eatable{
     public void eat(){
        // 天天吃米饭,真幸福啊!!
     }
}

class Chicken implements Eatable{
     public void eat(){
        // 如果天天吃鸡,那就是黄鼠狼啊!!
     }
}

// 上层使用者,只需要知道接口,根据配置文件在运行时加载需要的类

class You{
     private Eatable meal;
     public void eatmeal{
        Resource rs =new ClassPathResource(”beans-config.xml”);// 加载配置文件
        BeanFactory factory = new XmlBeanFactory(rs);         
        this.meal = (Eatable)factory.getBean(”eat”);
        this.meal.eat();         //可算开始吃饭了,但直到饭菜上桌才知道吃什么,哎,悲惨
     }
}
下面是beans-config.xml的主要内容

<bean id=”eat”
    class=”Chicken” > //这里就可以灵活改变了。
</bean>

    上面的代码基本演示了这个小故事和依赖注入等相关概念,但这并不是spring的标准开发,虽然这么做无可厚非,利用接口提供服务,并动态调用,这也是依赖注入的一种方式。However,spring只支持设值注入和构造注入,设值注入比较常用,如下更改就是spring的标准设值注入。

class You{
     private Eatable meal;
     public void setMeal(Eatable meal) {//一定要有setter
        this.meal = meal;
}

     public void eatmeal{
        //Resource rs =new ClassPathResource(”beans-config.xml”);// 加载配置文件
     //BeanFactory factory = new XmlBeanFactory(rs);         
       //this.meal = (Eatable)factory.getBean(”eat”);
        this.meal.eat();         //可算开始吃饭了,但直到饭菜上桌才知道吃什么,哎,悲惨
     }
}

而新的配置文件如下:

<bean id=”you” class=”You” >
<property name = “meal”>
<REF local = “eat”>   
</property>
</bean>
<bean id =”eat” class = “Rice”/>

这样改变以后,实现Eatable接口的类就会被spring的IoC容器动态注入到类You中,而类You也可以被包装成实现了某个接口的javabean,在更上层应用中使用那个接口来进行操作,而加载过程如出一辙。

在spring世界里,整个流程被框架化了,用配置文件把使用者和javabean或者bean与bean之间解耦。不管什么技术什么模式,要想解耦,一定会抽象出更多的中间层以增加间接性,直接的叫高内聚但是不灵活。为了灵活自己没事找事增加间接性。这就是spring干的事情。也是很多设计模式干的事。

那么回过头再说说,spring所体现出来的解耦,依赖注入是它的专利么?

这问题回答起来太干脆了:不是。在.NET世界,我们习惯使用反射来动态加载类,而在load时使用读配置文件的办法。这样高层的代码编译发布以后不用再变化,只需要改需要加载的装配件和配置文件就好了。

依赖注入就是把原先在一起但没必要在一起的两样东西分开,但是他们毕竟还是有关系的,所以我们就用胶水把他们再粘到一起。整个就是没事找事。

本文来自:http://www.cnblogs.com/windyitian/archive/2008/08/26/1276904.html 

一定要坚持[转]

08月 21st, 2008

两个旅行中的天使到一个富有的家庭借宿。这家人对他们并不友好,并且拒绝让他们在舒适的客人卧室过夜,而是在冰冷的地下室给他们找了一个角落。当他们铺床时,较老的天使发现墙上有一个洞,就顺手把它修补好了。年轻的天使问为什么,老天使答到:“有些事并不象它看上去那样。”
第二晚,两人又到了一个非常贫穷的农家借宿。主人夫妇俩对他们非常热情,把仅有的一点点食物拿出来款待客人,然后又让出自己的床铺给两个天使。第二天一早,两个天使发现农夫和他的妻子在哭泣,他们唯一的生活来源——一头奶牛死了。年轻的天使非常愤怒,他质问老天使为什么会这样,第一个家庭什么都有,老天使还帮助他们修补墙洞,第二个家庭尽管如此贫穷还是热情款待客人,而老天使却没有阻止奶牛的死亡。
“有些事并不象它看上去那样。”老天使答道,“当我们在地下室过夜时,我从墙洞看到墙里面堆满了金块。因为主人被贪欲所迷惑,不愿意分享他的财富,所以我把墙洞填上了。昨天晚上,死亡之神来召唤农夫的妻子,我让奶牛代替了她。所以有些事并不象它看上去那样。”
有些时候事情的表面并不是它实际应该的样子。如果你有信念,你只需要坚信付出总会得到回报。你可能不会发现,直到后来……  

PHP缓存加速比较[原创]

07月 31st, 2008

网上好多关于PHP缓存加速的比较,我最近也做了个测试,仅供大家参考.

PHP 是一种描述程序语言(scripting language),当执行一个PHP原始码的时候:

1.PHP 系统把原始码加载内存
2.剖析原始码并把它转换成作业码(一种可以被PHP系统执行的程序代码)
3.执行作业码
4.释放内存

每一次我们连结到服务器下载页面,服务器执行一个或多个 PHP 程序,每一个程序每次都要重复以上三个步骤,这是描述程序语言一般的运作方式.除非我们正在进行系统开发或者除错,否则我们很少会在系统运行期间不断修改程序,不停重复上述的步骤显然毫无意义,这就是 PHP 加速器发挥功能的时候. 加速器会把作业码储存在内存或者磁盘上,当执行同一个原始文件时,加速器会检验原始文件自从上次加载后有否更改过,没有的话便直接执行储存的作业码,否则便按正常的步骤把原始码加载、转换、及执行. 部分加速器兼具优化作业码的功能,例如把无用的循环、变量删除,这对程序的执行效能有帮助.在这里我们只比较2个比较流行的加速器:

APC:全称是Alternative PHP Cache,是 PHP 的一个免费公开的优化代码缓存。它用来提供免费,公开并且强健的架构来缓存和优化 PHP 的Opcode(Operation Code操作代码) 。http://www.php.net/apc/
 
eAccelerator:开放原始码,它的前身是truck-mmcache http://eaccelerator.net/

其实还有2个不错的加速器:一个是xcache,但是,因为这个加速器推出的时间不长,考虑到稳定性,暂时不参与测试.另一个是Zend Platform 是唯一有商业性支持的加速器,若果你需要良好的支持而又负担得起,不妨考虑 Zend Platform.
比较 APC 和 eAccelerator 的效能

测试环境:
AMD Opteron(tm) Processor 265 1.8 GHz(双核)
2 GB RAM
Apache 2.2.8 
PHP 5.2.5
eAccelerator 0.9.5.3
APC 3.0.16

eAccelerator配置:
extension=eaccelerator.so
eaccelerator.shm_size=”512″
eaccelerator.cache_dir=”/tmp/eaccelerator”
eaccelerator.enable=”1″
eaccelerator.optimizer=”1″
eaccelerator.check_mtime=”1″
eaccelerator.debug=”0″
eaccelerator.filter=”"
eaccelerator.shm_max=”0″
eaccelerator.shm_ttl=”0″
eaccelerator.shm_prune_period=”0″
eaccelerator.shm_only=”1″
eaccelerator.compress=”1″
eaccelerator.compress_level=”9″

apc配置:
extension=apc.so
apc.enabled=1
apc.shm_segments=1
apc.shm_size=32
apc.optimization=0
apc.num_files_hint=1000
apc.user_entries_hint=4096
apc.ttl=0
apc.user_ttl=0
apc.gc_ttl=3600
apc.cache_by_default=0
;apc.filters=
;apc.mmap_file_mask=/tmp/apc.XXXXXX
apc.slam_defense=0
apc.file_update_protection=2
apc.enable_cli=0
apc.max_file_size=”1M”
apc.stat=1
apc.write_lock=0
apc.report_autofilter=0
apc.include_once_override=0
apc.cache_by_default=1

 
3个测试程序:(/usr/local/apache2/bin/ab -c 20 -n 5000)
1.简单的运算程序
php(not)
Requests per second:    3058.03 [#/sec] (mean)
eaccelerator
Requests per second:    4387.60 [#/sec] (mean)
apc
Requests per second:    4428.36 [#/sec] (mean)
2.discuz 论坛首页
php(not)
Requests per second:    82.60 [#/sec] (mean)
eaccelerator
Requests per second:    361.07 [#/sec] (mean)
apc
Requests per second:    343.12 [#/sec] (mean)
3.程序更新
apc 当参数 apc.stat=0 每次不检查更新时:Requests per second:    4123.85 [#/sec] (mean)
    当参数 apc.stat=1 每次不检查更新时:Requests per second:    5334.26 [#/sec] (mean)
eaccelerator 对程序更改没有影响.

总结:
eAccelerator 与apc 在php程序加速方面可以说不分伯仲.对于简单的运算程序2个加速软件没有起到什么作用,当程序比较复杂的时候,加速效果明显.apc对被加速的程序有修改时,性能会有影响,同时eAccelerator的应用比apc广泛,文档更完善,而且能和ZendOptimizer结合使用(apc与ZendOptimizer冲突).但是apc是php开发团队维护的一个项目,在yahoo网站有着广泛的使用,前途也很不错的.

nginx比较流行了

07月 15th, 2008

nginx 一个不错的web服务器.最近很流行.处理的连接数是apache好几倍.内存占用很低.

但是我很少用它.因为在做一些项目中稳定是压倒一切.

最近偶然玩了一下web版的武林三国,碰上一个错误信息.发现也是用nginx做服务器的.

我是不是有时间也研究一下那…

互联网需要宽容

07月 7th, 2008

前一段时间,关于地震中的警察妈妈是否提干问题,引起了不少非议.我认为,这个问题没必要引起大家那么关注.

在网络上谩骂和挑刺渐渐的成了主流.我估计就算是完美无瑕的圣人,在网络上也会被批,因为他太完美.

谁要是范了一点错误被网络曝光,小恶也变成十恶不赦.众口铄金其利断金.

希望能善用网络的监督功能.不要让他成为一滩浑水…