2009年6月4日星期四

MyISAM几个容易忽视的配置选项

MyISAM在读操作占主导的情况下是很高效的。可一旦出现大量的读写并发,同InnoDB相比,MyISAM的效率就会直线下降,而且,MyISAM和InnoDB的数据存储方式也有显著不同:通常,在MyISAM里,新数据会被附加到数据文件的结尾,可如果时常做一些UPDATE,DELETE操作之后,数据文件就不再是连续的,形象一点来说,就是数据文件里出现了很多洞洞,此时再插入新数据时,按缺省设置会先看这些洞洞的大小是否可以容纳下新数据,如果可以,则直接把新数据保存到洞洞里,反之,则把新数据保存到数据文件的结尾。之所以这样做是为了减少数据文件的大小,降低文件碎片的产生。但InnoDB里则不是这样,在InnoDB里,由于主键是cluster的,所以,数据文件始终是按照主键排序的,如果使用自增ID做主键,则新数据始终是位于数据文件的结尾。

了解了这些基础知识,下面说说MyISAM几个容易忽视的配置选项:

concurrent_insert:

通常来说,在MyISAM里读写操作是串行的,但当对同一个表进行查询和插入操作时,为了降低锁竞争的频率,根据concurrent_insert的设置,MyISAM是可以并行处理查询和插入的:

当concurrent_insert=0时,不允许并发插入功能。
当concurrent_insert=1时,允许对没有洞洞的表使用并发插入,新数据位于数据文件结尾(缺省)。
当concurrent_insert=2时,不管表有没有洞洞,都允许在数据文件结尾并发插入。

这样看来,把concurrent_insert设置为2是很划算的(不过MySQL4版本并不支持2这个设置),至于由此产生的文件碎片,可以定期使用OPTIMIZE TABLE语法优化。

max_write_lock_count:

缺省情况下,写操作的优先级要高于读操作的优先级,即便是先发送的读请求,后发送的写请求,此时也会优先处理写请求,然后再处理读请求。这就造成一个问题:一旦我发出若干个写请求,就会堵塞所有的读请求,直到写请求全都处理完,才有机会处理读请求。此时可以考虑使用max_write_lock_count:

max_write_lock_count=1
有了这样的设置,当系统处理一个写操作后,就会暂停写操作,给读操作执行的机会。

low-priority-updates:

我们还可以更干脆点,直接降低写操作的优先级,给读操作更高的优先级。

low-priority-updates=1


综合来看,concurrent_insert=2是绝对推荐的,至于max_write_lock_count=1和low-priority-updates=1,则视情况而定,如果可以降低写操作的优先级,则使用low-priority-updates=1,否则使用max_write_lock_count=1。

参考资料:

Concurrent Inserts
Table Locking Issues

2009年5月15日星期五

I’m sorry but Dreamweaver is dying

I’ve received a number of very kind emails regarding my last digital design column, but I have to admit that a couple made me feel slightly uncomfortable.

These were the emails from designers thanking me for pointing them in the direction of Dreamweaver when they were making the transition from print to web design. It was a decision that they had come to appreciate greatly over the years, providing them with the best possible platform for their web design careers.



The problem is that Dreamweaver is dying…


To be fair it’s not Dreamweaver’s fault. Nor is the problem Adobe and its development team - the last Dreamweaver CS4 version was the most impressive release in years. Moreover, although Microsoft Expression Web poses a far more credible threat than FrontPage could muster, Dreamweaver remains the best HTML/CSS page-based editor available.

The real problem for Dreamweaver and for its users is that the nature of the web is changing dramatically. Dynamically-generated web applications, from Amazon right down to the humble blog, all offer much more – in-built commenting, voting, RSS feeds, etc - than the best sites built on static HTML can ever hope to provide.

This isn’t a matter of bells and whistles, it’s absolutely fundamental. Ultimately a web site is all about content - posting it and making it findable – and Dreamweaver and the other static HTML editors have proven fundamentally flawed when it comes to these two core tasks (and features such as Dreamweaver’s libraries and templates are patches not solutions).

The bottom line is that the old model of the central webmaster hand-spinning every page of every website and, worse, manually adding the navigation necessary to help users find it, just isn’t scalable or viable. The only feasible course for the future is for content to be posted by the content contributor, whether that’s the site owner or site visitors, and for the best possible navigation to be constructed around that content on the fly.

In other words Web 2.0 isn’t an empty slogan, it marks a fundamental break with the past and Dreamweaver lies on the wrong side of it. So is this the end for Dreamweaver and the traditional Dreamweaver-based web designer?

Eventually yes. In the relatively near future every website will be a dynamically-generated web application and all of today’s sites built on multiple static pages will be ripped out and replaced.

The good news of course is that this is actually a huge opportunity – think Klondike gold-rush - for the web designer who can adapt. But how? After all your average designer is built along radically different lines to your average developer.

But it can be done. Just as Dreamweaver eased the transition for print-only designers to the new markup-based world of HTML; content management systems such as Joomla and Drupal can ease the transition for static Web 1.0 designers to the new Web 2.0 world of script-based PHP. Give them a chance and you’ll be amazed at what you can achieve and all without touching a line of code (that can come later just as it did with Dreamweaver).

I really can’t recommend this strongly enough. If you are a Dreamweaver user don’t bother upgrading to the latest version or exploring Adobe’s feeble attempts to graft end user content contribution onto Dreamweaver. Instead save your money and invest your time in getting to grips with the real future of web design: server-based content management systems.

Dreamweaver is dying. Long live Drupal.

Tom Arah

——————————–

Well this article has generated a lot more comment than I was expecting (including on slashdot and digg) which is in itself a nice demonstation of web 2.0 in action and how Dreamweaver and static publishing in general is being left behind.

A lot of the comments are pretty much repeating themselves so I’m promoting the main points of an earlier response made below to try and clarify things and nip a few in the bud:

Comparing Dreamweaver and Drupal isn’t mad – they are both tools for producing websites.

Thinking about it I can see why people might assume they are entirely different - after all a cms is for producing a blog right? Absolutely not. You can reproduce any static site dynamically with a cms including simple and attractive brochureware sites.

Crucially you can’t do the opposite. This means that by using Dreamweaver you are denying your clients a lot of functionality - in-built commenting, rss feeds etc (only if you want them) - but most importantly end user content contribution and optimal on-the-fly navigation.

You’re also denying them the tag-based keywording that helps the search engines understand what your site is about. Google and cms go hand in hand and ultimately your job is to generate traffic.

Having said that it’s true that most cms sites currently do look and behave like blogs. More than that they look atrocious (most don’t even change from the default theme). There’s absolutely no reason why they should look so bad and that’s the other part of the equation and of my argument: current static designers have a lot to gain from cms but current cms also has a lot to gain from an influx of good design.

Clearly this post was aimed at the vast majority of Dreamweaver users - those designers producing static sites HTML page by HTML page. I wasn’t really addressing the developer and yes one of Dreamweaver’s great strengths has always been that it also caters for other languages and those developers manually building up their own dynamic sites.

And cms has even more to offer these users! Why reinvent the wheel and create your web application from scratch when you can take advantage of vast communal development effort that lets you achieve results that you couldn’t begin to dream of when working on your own?

Even with the fundamental shift to cms that I’m talking about there remains a role for an application to help users produce the cms logic and the CSS templates in the first place. And I’m sure a lot of the cms modules and most of the css templates were and will continue to be built in Dreamweaver.

But it’s precisely because these are then given freely to others to use and adapt that Dreamweaver becomes redundant for the vast majority of users. No one is going to pay for Dreamweaver with all its baggage if all they want to do is tweak a few lines of code. Especially as this is already more effectively done live in the browser.

Finally I carefully didn’t say that Dreamweaver is dead. To begin with, from some of the comments, it’s clear that there’s a lot of ignorance, inertia and self-interest to be overcome.

More importantly, as others have sensibly pointed out, these are early days and the cms options as they stand are currently only ready for early and adaptable adopters, not for the mainstream. You certainly shouldn’t expect to be able to switch instantly - I’m advising rethinking and retraining.

All in all Dreamweaver will be around for a while yet. However it used to be the dominant web force and the secret behind the overwhelming majority of professional web sites and it won’t be in the future.

The future for creating web design is in the browser not in Dreamweaver.

—————————–

Unsurprisingly Adobe has a slightly different take on things and I’ve now added a follow-up post based on a chat with Devin Fernandez, senior product manager for the web products at Adobe

2009年4月23日星期四

谈谈图片的存储架构

1,分域名,因为IE有同一域名的并发的限制。
2。图片服务器与web服务器要分离。。用轻量的web服务器,如lighttpd
3.图片服务器,对IO要求高。。磁盘要好一点。
4。http header过期时期设置长一点。
5,目录存储,我喜欢用用户创建时间的year/month/day去目录分离
6.页面读出图片的时,最好用flash异步去读取,不去占web页面的下载时间。


还有个防盗链的问题。

2009年4月7日星期二

PHP snippets

Here we got a fricking sweet function from PHP5(not sure though):

function test($aa,$bb)
{
$arg_list = func_get_args();
print_r($arg_list);
}

test(1,2);
?>

This func simply gets every parameter which the function it was put in gets.

2009年3月23日星期一

前段控制器是邪恶的吗?

所谓前端控制器(FrontController),是指一个请求运行的公共起点,并且在这里决定下一步执行什么。多数PHP框架里都实现了它。统一进行权限限制,会话管理等等公共操作,并且进而通过一个类似路由的装置,把请求委派给一个具体的命令对象来执行。实现方式上,前端控制器通常是以一个名为index.php的文件为载体,通过重写规则把请求都转发到这个文件上,如CakePHP在Apache上的设置:








RewriteEngine On


RewriteCond %{REQUEST_FILENAME} !-d


RewriteCond %{REQUEST_FILENAME} !-f


RewriteRule ^(.*)$ index.php?url=$1 [QSA,L]








不过老话说,物极必反,随着前端控制器使用的泛滥,越来越多的人开始质疑PHP开发是否有必要使用前端控制器。这里以PHP之父Rasmus Lerdorf的影响最大,早些时候,他在Simple is Hard里陈述了如果想开发出有扩展性的Web应用,必须保证架构是Share-nothing Architecture:





Share-nothing Architecture


* Like HTTP, each request is distinct


* Shared data is pushed down to the data-store layer


* Avoid front controllers








Rasmus Lerdorf的看法:


在Rasmus Lerdorf看来,想要让一个网站具有良好的扩展性其实是非常简单的,只需将网站应用分成若干个独立小程序,前端透过API提供服务,后端是应用程序引擎,这样做自然会有扩展性。因为应用的每一个部分,都有不同等级的使用方式,需要有不同的扩充程度,需要不同的机制来处理。以开发雅虎电子邮件而言,是要开发一个地址服务程序、一个读信服务、一个送信服务,而送信程序完全和读信程序无关。以雅虎的规模而言,需要让这些工作完全分离,才有扩充性。这里的关键是你必须建立分离、模块化的独立端点,而不是全部放在同一个大篮子里。大多数现今开发框架,都使用了前端控制器,每一次浏览器发出请求时,就会调用这个前端控制器,再由前端控制器来分辨,使用者想要执行哪一支程序。这样做,一点意义都没有。在浏览器层次,程序完全能知道用户想要做什么事情,例如使用者只是要读信,程序就不用再把需求送到服务器,让服务器判断使用者要读信还是送信。将这类决策工作拉出浏览器,由服务器处理,就会浪费大量服务器资源,来处理那些对用户没有实际功用的工作。







我的看法:
我绝对相信Rasmus Lerdorf对于系统可扩展性的论述。但是我觉得他对于前端控制器合理性的判断太过武断。诚然,在浏览器的层面就完成了所有路由的工作有很好的可扩展性,但是在不同的请求里都进行权限限制,会话管理等等公共操作也变得重复了。而且,Rasmus Lerdorf对于前段控制器的论述是建立在一个假设条件上的:网站仅有一个前端控制器,并且仅运行在一台服务器上,所有的请求都要经由这台服务器再进行分发。如果真是这样,那么前端控制器必然会引起单点瓶颈,但事实上我们在实际使用前端控制器的时候,完全可以把代码拷贝到若干台服务器之上,请求均匀的分发到这些服务器上,此时的前端控制器只是程序逻辑上的单点,在物理架构上,是不存在瓶颈的,对扩展性没有影响。而且,系统里是可以有多个前端控制器的,比如说一个网站里可以有文章系统前端控制器,论坛系统前端控制器,用户系统前端控制器,这样压力自然就得以分散。当然,一不留神还是会遭遇一些前端控制的使用障碍,比如说路由无限扩张的问题:通常,使用前端控制器的时候,需要通过路由设定来映射URL和Action的关系,随着系统的膨胀,路由设定的内容会越来越多,每当一个请求过来的时候,都要从头解析路由设定以找出符合本次URL映射的Action,如果路由设定内容很多的话,这无疑是个巨大的负担,想要规避这个问题也没有太好的方法,只能是尽可能精简的使用自定义路由的功能。

总结:
牢记Rasmus Lerdorf的教诲是有意义的,但前端控制器并不邪恶,在了解它的优缺点后,合理的使用,既能保持程序的美感,又不丧失架构的扩展性。

2009年3月20日星期五

在企业里,逻辑本身常常让人困惑。

有这样一家公司,它已发展十年,从早期的一年营业额400万元,到今天可能一天的营业额就超过这个数字。去年,它首次跨过了盈亏平衡线,并且依然保持着“全球最大的中文网上书店”的称号。
实事求是地讲,这样的成绩并不算难看。于是,在最近我们杂志发表了一篇名为《当当:错过黄金十年?》的文章后,遭到了该公司的强烈抗议,一些主流门户网站也在压力下撤掉了稿件。
媒体是苛刻的评判者。我们之所以“危言耸听”地称其可能沦为“二流的互联网公司”,是因为我们看到了更多的“月之暗面”。
第一,当当效仿的“美国偶像”Amazon已经成为全球最具影响力和创造力的互联网公司,年营收191亿美元,净利润6亿多美元。而中国最早的B2C探路者却连上市都一直未能如愿,更遑论其它。
第二,在年增速超过48%的中国B2C市场上,5年前还占据40%以上份额的当当如今只有12%了,在它之上的有淘宝商城、京东商城,还有旗鼓相当的对手卓越亚马逊,以及北斗、麦网、红孩子、Vancl等一批紧追的对手(以上数据来自艾瑞和易观国际)。
第三,只有在传统的出版物网购市场上,当当的占有率超过第二名卓越亚马逊10%。但问题在于,这个市场早已不再是B2C生意的全部,整个蛋糕中它只占有18%,而日用百货和3C产品合计获得了接近70%的份额。可当当80%以上的业务还在出版物这一块(目前Amazon的相关业务只占到总销售额的57%)。结果是,当当从未像新浪对付雅虎中国、淘宝对付eBay易趣、百度对付谷歌、QQ对付MSN一样,把它的国际对手牢牢压在身下。
当然,棋至中盘,现在就断定输赢,可能还为时尚早。但在我看来,十年当当的身上,其实承载着一些看似悖论的商业命题:主动求变还是坚持不变;生存第一还是发展第一;做好产品还是做大平台;控制权更重要还是舞台更重要。
而个中的权衡取舍,又跟行业本质、竞争环境,乃至创始人的性格心态息息相关。
变还是不变
一个最基本的问题:B2C电子商务到底是属于IT互联网还是零售业?贝索斯的答案早就有了,“亚马逊是一家IT公司”,“我们要做电子商务的孵化器”。我们问俞渝,她说“我们做的是零售业,互联网只是工具。在这个行业里,沃尔玛是九段,我们顶多是三段”。
互联网和零售业是两个本质截然不同的行业。巴菲特大叔是喜爱零售业的,因为它的产业结构变化缓慢,企业更容易确立起“护城河”,如果你能像沃尔玛一样坚持“天天平价”50年不变,铁杵也能磨成针了。
他害怕互联网,因为这是年轻人的专利。变化太快,创新太容易,可能一夜之间就能起来一个巨人,统治者也可能在一夜之间倒下。互联网没有围墙,强调的是眼球经济学、长尾和免费万岁,想尽办法先让消费者的福利最大化,然后才能构建商业模式。只有让他们先爽了,他们才愿意送钱过来。
本质上,零售业更适合PE投资,只有你的雪球已经滚到足够大的时候,别人才会来帮你。而VC天生就跟IT互联网如影随形。他们干的就是赌博,十个车库小子里,有一两个成功就OK了。
零售业的胜利往往是成本和细节的胜利,绝不碰赔钱赚吆喝的生意,就算毛利率再低,也得从毛巾里拧出利润来才行。而互联网的胜利首先是思想的胜利。陈天桥就说过他最害怕的竞争对手,不是他面前的谁谁谁,而是某个角落里埋头苦干的年轻人。
所以,你可以理解俞渝为什么不看好那些以互联网方式扩张的同行,比如以300%速度成长的京东商城,“一个无法长期做下去的生意,平进平出,做生意再低也要有一个利润”。
十年前,俞渝和李国庆写的商业计划书里想干三件事:图书音像、信息服务、媒体价值。十年以后,俞渝承认,“我们只做到了第一个。剩下两个都没有做成功”。再问俞渝,未来做什么?“下一个十年,当当还会坚持现在的模式,只是产品更加丰富。”
但在互联网业里,坚持在大多数时候都不是正确的。如果马化腾仅仅满足于做一个IM软件的开发商,那么腾讯会成为今天中国市值最大的互联网公司吗?如果马云不做淘宝和支付宝?如果百度不做贴吧、知道、MP3?如果盛大只运营《传奇》游戏? 它们还是今天的它们吗?
同一件事情,看的高度和角度不同,就会产生不同的理解,又进而决定不同的行为方式。
生存第一还是发展第一
前一阵跟土豆的王微交流。他讲自己的亲身故事。2005年刚开始做视频的时候,连他自个在一起就5条人枪,IDGVC给了50万美刀。2006年5月B轮融资850万美元完成,也才20来个人。当时,他跟JAFCO(集富亚洲)的投资人说,这钱够做个三年,一步步来。结果没想到,当年10月,Google宣布16亿美金收购Youtube,马上无数国人跟进。王微不得不改变策略,隔几个月就动手融一次资(2007年4月C轮1900万美元,2008年4月D轮融资5700万美元),也没有什么对赌协议,就是最简单的拿股份换资本,根本没有什么年度计划,只有月度顶多季度计划,不管外界怎么说,就是要用百米冲刺的速度抢跑。
当时早期一块起来的某同行放话说,不跟风,不烧钱,要用长跑的心态去做事。结果今天,这位同行虽然还有现金没花完,但已经没人把他们当棵菜。而土豆牢牢占据了市场前两把交椅,投资者也只认前两名。“我们毕竟没有那么深的口袋,一旦别人超出你一大截之后,就很难追上。”
“从去年下半年开始,我们有年度计划了,控制速度,巩固基础,学会赚钱。因为我已经从同类的对手中跑出来了,现在我关注的是QQ、新浪、搜狐甚至央视。他们每一个都比我大很多。”他微笑着讲。
在快速变化的新兴产业里,竞争就不是自己跟自己较劲,更不是你和对手两家下围棋,更像是四国军棋甚至海陆空混战,对竞争形势和大环境的判断就变得非常重要。
3G门户的张向东跟我谈过类似的观点。他参观日本最赚钱的无线互联公司DeNA和MIX,很感慨的一点就是:对方的产业环境、商业文化比我们好。只要你找到了一条成功的道路,其它对手就会自动地选择其它道路去摸索。不会“一窝蜂”地冲上去。“所以人家PV流量虽然不如我们,应用也没我们多,但赚钱比我们容易多了。”
没人能教你如何在乱中取胜,如何抢装备抢地盘,什么时候冲锋,什么时候卧倒,怎样在看似没可能的情况下过江,你只能依靠自己的本能、直觉和运气,就跟《我的团长我的团》里面的龙文章一样。美军教官也教不了这些东西。
真正第一流的公司会抢在市场变化之前调整节奏,第二流的公司始终只会坚持一种节奏,而第三流,则只能跟着市场做随机的布朗运动。
其实,商界跟时尚界无二。前几年,高速成长、追逐高风险高回报的“快公司”倍受追捧,金融风暴之后,昔日明星被纷纷打入冷宫,而谨慎保守、现金为王的“慢公司”似乎又成为业界欣赏的对象。
的确,相比曾经喧嚣一时的8848和PPG,坚持一种节奏的当当看上去更值得尊敬。但我相信这很大程度上只是因为人们的心态发生了变化。保守成为不冒进的代名词。
如今,人人都知道,现金是奶妈。但你不能永远躺在奶妈的怀抱里。你可以裁人裁到只剩你和CFO、砍掉一切面向未来的业务,只保留一间办公室,这样也许能让你的公司活100年。但这有意义吗?你可以忘掉市盈率,但你还得考虑回报率。
没有投入企业就无法发展,如果资金投入后,未来3年有30%的回报,你冒不冒险?投资商关注的可不是你保存了多少现金,而是你能否把现金用好,真正构建起你的竞争力优势,在环境复苏的时候,成为最大的受益者。
所以,当俞渝很自豪地告诉我们,“我们第三轮融资的钱还放在银行里,发愁的是选什么理财产品”的时候,我在轻叹,如果不知道怎么用,干嘛选择股权融资这种最昂贵的选择?
特定情境下,生存和发展就是一对悖论。不做是等死,做是找死。中国的第一流创业家,大多找过死。张朝阳、丁磊、李彦宏、马化腾、陈天桥、史玉柱等等,都有过濒死体验,敢置之死地而后生的,才有机会大成。你敢吗?
做产品还是做平台
不管是做平台的陈天桥、马云、李彦宏,还是做产品的丁磊、马化腾,两条道路都是可以成功的。
过去十年中,当当其实做过很多尝试,它们做过C2C的“当当宝”,干过分类信息和联营商城,也卖过衬衫,还尝试到进入唱片发行的渠道,但几乎全都浅尝辄止。平均每项新业务的寿命可能不超过半年。
在我看来,当当始终没有想清楚的一件事是“做好产品,还是做大平台”。
好吧,先说做产品。马化腾的意见是,产品的核心能力必须做到极致,让用户片刻难离,让对手望尘莫及。像QQ一样覆盖每台电脑的桌面,像《征途》一样让有钱人没钱人都上瘾。
用户对于B2C服务的实际需求其实就四条:品种够丰富、价格够低廉、购物够放心、送货够及时。但作为一个多年的VIP用户,我却不得不长期忍受当当的缺货,延期迟到,书籍的脏污皱折以及塑料提袋。如果俞渝总裁去百度贴吧看一下,相信这应该不是我个人的感受。因为当当并没有比对手做得更好,所以它不是不可替代的。
当你的核心产品比所有对手都要强的时候(市占率超过50%),你就可以扩展,从一个点扩散到一个面或者蔓延到整个链条,这才能让生意有持续的想象力。我不太理解的是,为什么俞渝认为当当不能做衬衫直销(“如果你要丰富产品就要有专业的团队,当当会变成一个服装公司了。”)我也不明白,为什么豆瓣也好,起点中文网也罢,都是别人做的事情,而不应该是当当做的事情。
假设当当真正深耕出版物这个市场。我查了一下,2007年,光中国图书出版市场的销售额就超过500亿元。作为全球最大的中文网上书店,如果能切掉十分之一的蛋糕,日子也可以过得很舒服了,甚至足以对产业产生影响。但当当却连1/50不到。
2007年,美国图书出版业的总销售额是250亿美元,而Amzon“媒体出版物业务”的北美营收数字是46亿美金。
回过头来说做平台,2005年,正式上线不过3天,“当当宝”宣布暂停卖家认证。俞渝当时的理由是,“四道贩子的个人交易模式不能带给用户真正的低价;出现危险商户,目前规则不能够保证消费者的权益,诚信形象将受到损失;违规商品出售,给客户购买造成风险;当当网服务的对象就是中国正在崛起的中产阶段,不低价、勿宁死,不诚信,就关门。”
没有诚信、物流很烂,支付系统不完善,这些都是客观环境。但它们不是理由,摆在你面前的问题,也摆在你的对手面前。马云说过一句话:如果银行不改变,我们改变银行。今天,支付宝的确在改变银行。
当当也想过做B2C的平台。但做平台商,得有服务意识。就跟中关村的电子市场一个道理,你门脸越大,停车越方便,配套越齐全,人流才越多,大家才有钱赚,你才能收租。而我在当当的联营商户上订过鲜花,结果晚了足足两周才送到。理由是当当只出租虚拟店面。物流配送客户自己做的。
现在,当当再想做B2C平台已经很难了,因为众多的品牌大企业已经跟随淘宝商城而去,后者通过C2C带来的用户流、阿里旺旺、支付宝已彻底压倒了当当。
其实,当当不必“要到外太空寻找成功的榜样”,看看Amazon,看看淘宝,看看腾讯,就该知道自己到底做得怎么样?
控制权更重要还是舞台更重要
关于创始人和投资人斗智斗勇的故事,一直是商业媒体最喜爱的题材。通常情况不外以下几种:1,投资人不满创始人工作不力,另立新主,杯葛创始人,比如中华英才网;2,创始人与投资人严重意见分歧,最后一拍两散,投资人主动退场,比如盛大;3,创始人A与投资人C、D联手,做掉创始人B,比如新浪;4,创始人把投资人哄入场,把投给A公司的钱秘密输送到自己名下的B公司,最后创始人和投资人两败俱伤,比如亚洲传媒……
核心是控制权的问题。创始人(Founder)是不是一定要做CEO,企业一旦接受了投资,还是不是创始人说了算的企业。
在硅谷,游戏规则比较透明。选贤任能,大家比较能够坦然接受事实。也尊重合同,条款里把丑话都写在前头。
当当也算经历过反复折腾的公司,李国庆甚至曾以辞职相威胁。而最终的结果,是经历三轮融资之后,两夫妻仍然控制着50%以上的股份。“如果你对当当的行为感到费解,那只是因为你对这个公司并不了解。”一位离职的当当中层告诉我们。在这个控制权高度集中的公司,几乎没有人能影响俞渝和李国庆的决定,不管你是投资人还是副总裁。
好的一面,创始人不用再听投资人指手画脚,可以完全按照自己的意志来做事;坏的一面是,创始人的境界决定了这个企业的天花板。
心有多大,舞台就有多大。如果你就愿意小富即安,这是你的追求,别人也无权责备你。但互联网又的确是一个制造梦想的行业,所以特别适合雄心勃勃的年轻人。
贝索斯是做对冲基金出身的,见惯了大赢大输。无论在上市前,还是在上市后,Amazon从未停止过大手笔的投资。从最早的网上书店,到音乐、玩具、拍卖商店,再到zShop店中店,再到投入巨资构筑物流平台、云计算平台,而Kindle更可能变成出版物的数字平台。所有这些都不是华尔街希望贝索斯做的,是贝索斯逼着华尔街认可的。(现在,所有Amazon内部人持有的股份是23%)。
所以,KPCB的“VC教父”John Doerr一直挺他到现在,是Amazon的董事会成员,还拿着不少其股票。而Amazon也是硅谷大公司里少有几个创始人一直干CEO到现在的。
李国庆在创办当当前,是有十年图书出版经验的“老江湖”。俞渝在华尔街干过多年,专长是做债券融资,一名石油客户给俞渝的评价是从来不能在油田找到利润,却能在铅笔间上找到利润。
一个对行业熟悉,另一个关注细节,两人的特点都是低头做事,不抬头望天。2005年,卓越亚马逊还因为艰苦整合而一片混乱的时候,当当却没有抓住机会彻底打垮对手。现在,当当的先发优势和主场之利不再,而卓越亚马逊的系统优势开始显现。
在互联网业,最好的防守就是进攻。企业做到一定时候,必须跨越甚至自废武功,去做新的。心脏不好的人干不了。丁磊和马化腾是国内两个出名的谨慎派,但做新业务从不手软。
拿破仑有句名言:不想当将军的士兵不是好士兵。但显然,能够最后成为将军的士兵万千人中才有一个。“彼得定律”的解释:大多数人都会一直爬升,直到一个你不能胜任的位置而停滞下来。
创业或许同样如此,绝大多数个体会在通往巅峰的道路上半途而废。几个伟大人物改变世界,少数一流人物可以影响世界,一些二流的人物为自己和员工改善生活,而三流四流者则是在徒耗资源。

2009年3月15日星期日

PHP autoload机制详解

关于SPL的autoload的函数手册,请参考 SPL函数手册:

http://www.phpinternals.com/blog/2008/12/translate-refs-spl-functions/

(1) autoload机制概述

在使用PHP的OO模式开发系统时,通常大家习惯上将每个类的实现都存放在一个单独的文件里,这样会很容易实现对类进行复用,同时将来维护时也很便利。这也是OO设计的基本思想之一。在PHP5之前,如果需要使用一个类,只需要直接使用include/require将其包含进来即可。下面是一个实际的例子:

/* Person.class.php */
class Person {
var $name, $age;

function __construct ($name, $age)
{
$this->name = $name;
$this->age = $age;
}
}
?>

/* no_autoload.php */
require_once (”Person.class.php”);

$person = new Person(”Altair”, 6);
var_dump ($person);
?>

在这个例子中,no-autoload.php文件需要使用Person类,它使用了require_once将其包含,然后就可以直接使用Person类来实例化一个对象。

但随着项目规模的不断扩大,使用这种方式会带来一些隐含的问题:如果一个PHP文件需要使用很多其它类,那么就需要很多的require/include语句,这样有可能会造成遗漏或者包含进不必要的类文件。如果大量的文件都需要使用其它的类,那么要保证每个文件都包含正确的类文件肯定是一个噩梦。

PHP5为这个问题提供了一个解决方案,这就是类的自动装载(autoload)机制。autoload机制可以使得PHP程序有可能在使用类时才自动包含类文件,而不是一开始就将所有的类文件include进来,这种机制也称为lazy loading。

下面是使用autoload机制加载Person类的例子:

/* autoload.php */
function __autoload($classname) {
require_once ($classname . “class.php”);
}

$person = new Person(”Altair”, 6);
var_dump ($person);
?>

通常PHP5在使用一个类时,如果发现这个类没有加载,就会自动运行__autoload()函数,在这个函数中我们可以加载需要使用的类。在我们这个简单的例子中,我们直接将类名加上扩展名”.class.php”构成了类文件名,然后使用require_once将其加载。从这个例子中,我们可以看出autoload至少要做三件事情,第一件事是根据类名确定类文件名,第二件事是确定类文件所在的磁盘路径(在我们的例子是最简单的情况,类与调用它们的PHP程序文件在同一个文件夹下),第三件事是将类从磁盘文件中加载到系统中。第三步最简单,只需要使用include/require即可。要实现第一步,第二步的功能,必须在开发时约定类名与磁盘文件的映射方法,只有这样我们才能根据类名找到它对应的磁盘文件。

因此,当有大量的类文件要包含的时候,我们只要确定相应的规则,然后在__autoload()函数中,将类名与实际的磁盘文件对应起来,就可以实现lazy loading的效果。从这里我们也可以看出__autoload()函数的实现中最重要的是类名与实际的磁盘文件映射规则的实现。

但现在问题来了,如果在一个系统的实现中,如果需要使用很多其它的类库,这些类库可能是由不同的开发人员编写的,其类名与实际的磁盘文件的映射规则不尽相同。这时如果要实现类库文件的自动加载,就必须在__autoload()函数中将所有的映射规则全部实现,这样的话__autoload()函数有可能会非常复杂,甚至无法实现。最后可能会导致__autoload()函数十分臃肿,这时即便能够实现,也会给将来的维护和系统效率带来很大的负面影响。在这种情况下,难道就没有更简单清晰的解决办法了吧?答案当然是:NO! 在看进一步的解决方法之前,我们先来看一下PHP中的autoload机制是如何实现的。

(2) PHP的autoload机制的实现

我们知道,PHP文件的执行分为两个独立的过程,第一步是将PHP文件编译成普通称之为OPCODE的字节码序列(实际上是编译成一个叫做zend_op_array的字节数组),第二步是由一个虚拟机来执行这些OPCODE。PHP的所有行为都是由这些OPCODE来实现的。因此,为了研究PHP中autoload的实现机制,我们将autoload.php文件编译成opcode,然后根据这些OPCODE来研究PHP在这过程中都做了些什么:

/* autoload.php 编译后的OPCODE列表,是使用作者开发的OPDUMP工具
* 生成的结果,可以到网站 http://www.phpinternals.com/ 下载该软件。
*/
1: 2: // require_once (”Person.php”);
3:
4: function __autoload ($classname) {
0 NOP
0 RECV 1
5: if (!class_exists($classname)) {
1 SEND_VAR !0
2 DO_FCALL ‘class_exists’ [extval:1]
3 BOOL_NOT $0 =>RES[~1]
4 JMPZ ~1, ->8
6: require_once ($classname. “.class.php”);
5 CONCAT !0, ‘.class.php’ =>RES[~2]
6 INCLUDE_OR_EVAL ~2, REQUIRE_ONCE
7: }
7 JMP ->8
8: }
8 RETURN null
9:
10: $p = new Person(’Fred’, 35);
1 FETCH_CLASS ‘Person’ =>RES[:0]
2 NEW :0 =>RES[$1]
3 SEND_VAL ‘Fred’
4 SEND_VAL 35
5 DO_FCALL_BY_NAME [extval:2]
6 ASSIGN !0, $1
11:
12: var_dump ($p);
7 SEND_VAR !0
8 DO_FCALL ‘var_dump’ [extval:1]
13: ?>

在autoload.php的第10行代码中我们需要为类Person实例化一个对象。因此autoload机制一定会在该行编译后的opcode中有所体现。从上面的第10行代码生成的OPCODE中我们知道,在实例化对象Person时,首先要执行FETCH_CLASS指令。我们就从PHP对FETCH_CLASS指令的处理过程开始我们的探索之旅。

通过查阅PHP的源代码(我使用的是PHP 5.3alpha2版本)可以发现如下的调用序列:

ZEND_VM_HANDLER(109, ZEND_FETCH_CLASS, …) (zend_vm_def.h 1864行)
=> zend_fetch_class (zend_execute_API.c 1434行)
=>zend_lookup_class_ex (zend_execute_API.c 964行)
=> zend_call_function(&fcall_info, &fcall_cache) (zend_execute_API.c 1040行)

在最后一步的调用之前,我们先看一下调用时的关键参数:

/* 设置autoload_function变量值为”__autoload” */
fcall_info.function_name = &autoload_function; // Ooops, 终于发现”__autoload”了

fcall_cache.function_handler = EG(autoload_func); // autoload_func !

zend_call_function是Zend Engine中最重要的函数之一,其主要功能是执行用户在PHP程序中自定义的函数或者PHP本身的库函数。zend_call_function有两个重要的指针形参数fcall_info, fcall_cache,它们分别指向两个重要的结构,一个是zend_fcall_info, 另一个是zend_fcall_info_cache。zend_call_function主要工作流程如下:如果fcall_cache.function_handler指针为NULL,则尝试查找函数名为fcall_info.function_name的函数,如果存在的话,则执行之;如果fcall_cache.function_handler不为NULL,则直接执行fcall_cache.function_handler指向的函数。

现在我们清楚了,PHP在实例化一个对象时(实际上在实现接口,使用类常数或类中的静态变量,调用类中的静态方法时都会如此),首先会在系统中查找该类(或接口)是否存在,如果不存在的话就尝试使用autoload机制来加载该类。而autoload机制的主要执行过程为:

(1) 检查执行器全局变量函数指针autoload_func是否为NULL。
(2) 如果autoload_func==NULL, 则查找系统中是否定义有__autoload()函数,如果没有,则报告错误并退出。
(3) 如果定义了__autoload()函数,则执行__autoload()尝试加载类,并返回加载结果。
(4) 如果autoload_func不为NULL,则直接执行autoload_func指针指向的函数用来加载类。注意此时并不检查__autoload()函数是否定义。

真相终于大白,PHP提供了两种方法来实现自动装载机制,一种我们前面已经提到过,是使用用户定义的__autoload()函数,这通常在PHP源程序中来实现;另外一种就是设计一个函数,将autoload_func指针指向它,这通常使用C语言在PHP扩展中实现。如果既实现了__autoload()函数,又实现了autoload_func(将autoload_func指向某一PHP函数),那么只执行autoload_func函数。

(3) SPL autoload机制的实现

SPL是Standard PHP Library(标准PHP库)的缩写。它是PHP5引入的一个扩展库,其主要功能包括autoload机制的实现及包括各种Iterator接口或类。SPL autoload机制的实现是通过将函数指针autoload_func指向自己实现的具有自动装载功能的函数来实现的。SPL有两个不同的函数spl_autoload, spl_autoload_call,通过将autoload_func指向这两个不同的函数地址来实现不同的自动加载机制。

spl_autoload是SPL实现的默认的自动加载函数,它的功能比较简单。它可以接收两个参数,第一个参数是$class_name,表示类名,第二个参数$file_extensions是可选的,表示类文件的扩展名,可以在$file_extensions中指定多个扩展名,护展名之间用分号隔开即可;如果不指定的话,它将使用默认的扩展名.inc或.php。spl_autoload首先将$class_name变为小写,然后在所有的include path中搜索$class_name.inc或$class_name.php文件(如果不指定$file_extensions参数的话),如果找到,就加载该类文件。你可以手动使用spl_autoload(”Person”, “.class.php”)来加载Person类。实际上,它跟require/include差不多,不同的它可以指定多个扩展名。

怎样让spl_autoload自动起作用呢,也就是将autoload_func指向spl_autoload?答案是使用spl_autoload_register函数。在PHP脚本中第一次调用spl_autoload_register()时不使用任何参数,就可以将autoload_func指向spl_autoload。

通过上面的说明我们知道,spl_autoload的功能比较简单,而且它是在SPL扩展中实现的,我们无法扩充它的功能。如果想实现自己的更灵活的自动加载机制怎么办呢?这时,spl_autoload_call函数闪亮登场了。

我们先看一下spl_autoload_call的实现有何奇妙之处。在SPL模块内部,有一个全局变量autoload_functions,它本质上是一个HashTable,不过我们可以将其简单的看作一个链表,链表中的每一个元素都是一个函数指针,指向一个具有自动加载类功能的函数。spl_autoload_call本身的实现很简单,只是简单的按顺序执行这个链表中每个函数,在每个函数执行完成后都判断一次需要的类是否已经加载,如果加载成功就直接返回,不再继续执行链表中的其它函数。如果这个链表中所有的函数都执行完成后类还没有加载,spl_autoload_call就直接退出,并不向用户报告错误。因此,使用了autoload机制,并不能保证类就一定能正确的自动加载,关键还是要看你的自动加载函数如何实现。

那么自动加载函数链表autoload_functions是谁来维护呢?就是前面提到的spl_autoload_register函数。它可以将用户定义的自动加载函数注册到这个链表中,并将autoload_func函数指针指向spl_autoload_call函数(注意有一种情况例外,具体是哪种情况留给大家思考)。我们也可以通过spl_autoload_unregister函数将已经注册的函数从autoload_functions链表中删除。

上节说过,当autoload_func指针非空时,就不会自动执行__autoload()函数了,现在autoload_func已经指向了spl_autoload_call,如果我们还想让__autoload()函数起作用应该怎么办呢?当然还是使用spl_autoload_register(__autoload)调用将它注册到autoload_functions链表中。

现在回到第一节最后的问题,我们有了解决方案:根据每个类库不同的命名机制实现各自的自动加载函数,然后使用spl_autoload_register分别将其注册到SPL自动加载函数队列中就可了。这样我们就不用维护一个非常复杂的__autoload函数了。

(4) autoload效率问题及对策

使用autoload机制时,很多人的第一反应就是使用autoload会降低系统效率,甚至有人干脆提议为了效率不要使用autoload。在我们了解了autoload实现的原理后,我们知道autoload机制本身并不是影响系统效率的原因,甚至它还有可能提高系统效率,因为它不会将不需要的类加载到系统中。

那么为什么很多人都有一个使用autoload会降低系统效率的印象呢?实际上,影响autoload机制效率本身恰恰是用户设计的自动加载函数。如果它不能高效的将类名与实际的磁盘文件(注意,这里指实际的磁盘文件,而不仅仅是文件名)对应起来,系统将不得不做大量的文件是否存在(需要在每个include path中包含的路径中去寻找)的判断,而判断文件是否存在需要做磁盘I/O操作,众所周知磁盘I/O操作的效率很低,因此这才是使得autoload机制效率降低的罪魁祸首!

因此,我们在系统设计时,需要定义一套清晰的将类名与实际磁盘文件映射的机制。这个规则越简单越明确,autoload机制的效率就越高。

结论:autoload机制并不是天然的效率低下,只有滥用autoload,设计不好的自动装载函数才会导致其效率的降低。