南方网景
【南方网景】是提供网站建设、网页设计、推广优化和软件开发的互联网综合服务商
点击这里给我发消息 点击这里给我发消息
数据下载中,请稍后...
点击这里给我发消息 点击这里给我发消息
压缩网页载入时间:Web页面并行化的几点考虑
添加时间:2010-1-20
    关键词: 网站 网页 制作 ASP 开发 ASP.NET 技术 解决方案 模板

建立网站时,最常见的需求是将网页的载入时间最小化,例如,一般对主要页面的载入时间要求控制在0.5秒以内,当然网页载入时间是与许多因素关联的,如网络,缓存,Web服务器,脚本语言/代码,数据库访问等。当然我想要讨论在创建Web页面时对数据库的访问,我指的是动态Web页面,如使用PHP,Java/J2EE,Ruby和Asp(.NET)等创建的动态Web页面。

一个非常常见的编程风格是使用脚本段,如:

< html> < body>     Time now is < %= new java.util.Date() %> < /body> < /html> 使用当前时间的文本代替上面的“< %= new java.util.Date() %>”。

如果我制作了一个动态内容站点,比如使用Wordpress建立一个博客站点,需要生成多个动态内容,如最新的帖子,热门标签,帖子评论等,同样也会生成对数据库的访问,主要是查询数据库,我想这里不用再多说什么,大家都能理解了。

问题

在生成一些“重量级”的网页时,如在线报纸和书店,可能会涉及到多个查询,如你是否已经登录?我们是否有建议推给你?最新的主题是什么?你以前的兴趣是什么?你有朋友在线吗?你在网站上会产生什么内容?

我最近审查一个网站,每个页面产生的查询次数都大于500,我个人认为这是一个非常高的数目了,但这些查询确实都是需要的,问题是页面载入时间花了2秒。

经过调整,重写和使用索引后,页面载入时间下降到0.6秒,但这还不够快,问题是所有数据库访问都是串行的,它们需要并行起来。Web页面并行化的需求由此诞生。

MySQL为一个查询计算只能使用一个线程,但I/O却是支持多线程的,这就导致在标准的Linux发行版上,对于一个给定的Web页面,只有一个CPU可以使用。模板引擎是一个接一个地解析脚本段的,按顺序执行的,在Java中,一个JSP页面被重写为一个普通的Java Servlet类,脚本段成为主要的代码,HTML代码成为打印标准的输出,因此获得是线性执行代码。

即便是再先进的框架,其标准的方法还是线性的,例如,使用Spring框架,你有Java对象和控制器负责Web页面,可以避免在动态Web页面中使用脚本,只需要那些控制器提供的数据,因此如果使用Spring + Velocity,一个Web页面看起来就会是:

< html> < body>     Login time as recorded in DB is: ${user.loginTime}  < /body> < /html> 在预建user对象时调用getLoginTime()方法进行转换,但这个方法是如何工作的呢?

它会缓慢地初始化以便访问数据库得到答案吗?

在某些init()方法期间控制器会设置值吗?

控制器会设置值以响应Web页面的请求参数,并逐一解析它们吗?

上面的一切都是线性或是串行执行的。

如何并行?

Web页面并行化不是一件容易的事情,需要理解多线程编程,程序员需要了解竞争环境、死锁和资源缺乏问题等,不过这些在动态网页中一般不会成问题,有些编程语言对多线程编程提供了良好的支持,Java就是这样一门语言。

假设我需要产生一个10个查询来响应Web页面的请求,如使用Java,我们可以像下面这样编写代码:

CountDownLatch doneSignal = new CountDownLatch(10);   Runnable task1 = new Runnable() {      public void run()      {          user.setLoginTime(this.jdbcTemplate.queryForInt("SELECT ... FROM ..."));          doneSignal.countDown();      }  } ;   Runnable task2 = new Runnable() {      public void run()      {          headlines = getSimpleJdbcTemplate().query("SELECT * FROM headline WHERE...",              new ParameterizedRowMapper< Headline>() {                  public Headline mapRow(ResultSet rs, int rowNum)                  {                      Headline headline = new Headline();                      headline.setTitle(rs.getString("title");                      headline.setUrl(rs.getString("url");                      ...                  }              }          doneSignal.countDown();      }  } ;   ...   Runnable task10 = new Runnable() {      ...      doneSignal.countDown();  }  Executor executor = Executors.newFixedThreadPool(numberOfAvailableProcessors);  executor.execute(task1);  ...  executor.execute(task10);   doneSignal.await();   // Now fill in the Model  上面的代码其实相对较简单,可读性也比较好,它的意思是:

◆让我们创建10个任务,但不执行它们,仅仅是制定命令;

◆每项任务完成后,让CountDownLatch知道它已经完成(但记住我们还没有执行它);

◆我们创建或使用一个线程池,使用n个线程,n可以与我们的处理器数量进行关联;

◆我们要求线程池处理所有的线程,在处理过程中,要么是同时运行它们,要么有些是顺序执行,依赖于有多少线程可使用;

◆我们请求CountDownLatch进行阻塞,直到这10个任务都通知已经完成了;

接着执行下一批任务。

Spring有一个内置的TaskExecutor机制提供与上面说的线程池类似的解决方案。

我大多数时候都是使用的C/C++/Java,我不知道在PHP,Ruby,ASP.NET或其它语言该如何实现,上面的代码肯定不能拿去直接使用,我希望看到框架能够提供解决这个问题的方案,以便对于一般的Web开发都可以用上Web页面并行技术。

原文:The DB problem inherent to dynamic web pages

作者:Shlomi Noach

本文作者:未知
咨询热线:020-85648757 85648755 85648616 0755-27912581 客服:020-85648756 0755-27912581 业务传真:020-32579052
广州市网景网络科技有限公司 Copyright◎2003-2008 Veelink.com. All Rights Reserved.
广州商务地址:广东省广州市黄埔大道中203号(海景园区)海景花园C栋501室
= 深圳商务地址:深圳市宝源路华丰宝源大厦606
研发中心:广东广州市天河软件园海景园区 粤ICP备05103322号 工商注册