Hello World
Spiga

为ASP.NET MVC扩展异步Action功能(上)

2009-02-02 09:22 by 老赵, 14441 visits

本文将分为上下两部分,您也可以从《Extend ASP.NET MVC for Asynchronous Action》获得全部内容。

异步请求处理是ASP.NET 2.0中引入的高级特性,它依托IO Complete Port,对于提高IO密集型应用程序的吞吐量非常重要(详见原理描述性能测试)。但是目前ASP.NET MVC框架缺少异步Action功能,这也就是老赵经常挂在嘴边的那个“目前ASP.NET MVC所缺少的非常重要的功能”。在TechED 2008 China的Session中我曾经给出过一个所谓的“解决方案”,但是它复杂性之高使那个解决方案有太多限制。为了弥补TechED上的遗憾,以及准备.NET开发大会上的ASP.NET MVC最佳实践的Session,我在春节休假期间仔细思考了一下这方面的问题,得出了一个相对不错的扩展:完整,方便,并且非常轻巧——核心逻辑代码只有200行左右,这意味着绝大部分功能将会委托给框架中现成的内容,确保了扩展的稳定,高效并且拥有较好的向后兼容性。

值得一提的是,我在1/26号便基于ASP.NET MVC的Beta版本写出了这个扩展的第一个版本,而在不久之后微软发布了ASP.NET MVC RC。我在移植解决方案的过程中发现ASP.NET MVC RC在框架设计上进行了较大的改进,这使得我在构建扩展时的策略发生了些许变化。令人欣喜的是,RC版本的这些变化对于构建一个扩展,尤其是现在这种“低端”级别的扩展变得更加容易。ASP.NET MVC框架实现了它“到处可扩展”的承诺。

那么我们现在就来详细分析一下这个扩展的实现方式。

请求处理方式的改变

在制定基本改造策略之前,我们需要了解ASP.NET MVC框架目前的架构及请求处理流程。如下:

  1. 在应用程序启动时(此时还没有接受任何请求),将针对MVC请求的Route策略注册至ASP.NET Routing模块。此时每个Route策略(即Route对象)中的RouteHandler属性为ASP.NET MVC框架中的MvcRouteHandler。
  2. 当ASP.NET Routing模块接收到一个匹配某个Route策略的HTTP请求时,将会调用该Route对象中RouteHandler对象的GetHttpHandler以获取一个HttpHandler,并交由ASP.NET执行。MvcRouteHandler永远将返回一个MvcHandler对象。
  3. MvcHandler在执行时,将取出RouteData中的controller值,并以此构建一个实现了IController接口的控制器对象,并调用IController接口的Execute方法执行该控制器。
  4. 对于一个ASP.NET MVC应用程序来说,大部分控制器将会继承System.Web.Mvc.Controller类型。Controller类将会从RouteData获取action值,并交给实现IActionInvoker接口的对象来执行一个Action。
  5. ……

如果我们要将这个流程改造成异步处理,那么就要让它符合ASP.NET架构中的异步处理方式。ASP.NET架构对于异步请求的处理可以体现在好几种方式上,例如异步页面,异步Http Module等,而最适合目前场合的做法自然是异步Http Handler。为实现一个异步Handler,我们需要让处理请求的Handler实现IHttpAsyncHandler接口,而不是传统的IHttpHandler接口。IHttpAsyncHandler接口中的BeginProcessRequest和EndProcessRequest两个方法构成了.NET中的APM(Aynchronous Programming Model,异步编程模型)模式,可以使用“二段式”的异步调用来处理一个HTTP请求。

您应该已经发现,如果我们要支持异步Action,就必须根据当前的请求信息来确认究竟是执行一个IHttpHandler对象还是IHttpAsyncHandler对象。而在ASP.NET MVC框架在默认情况下是在Http Handler(即MvcHandler对象)内部进行控制器的检查,构造和调用。这为时已晚,我们必须讲这些逻辑提前到Routing过程中才行。幸运的是,ASP.NET Routing所支持的IRouteHandler就像是ASP.NET中的IHttpHandlerFactory,可以根据情况生成不同的Handler来执行。因此,我们只要构建一个新的IRouteHandler类型即可。于是就诞生了AsyncMvcRouteHandler——可以想象的出,其中的部分代码与框架中的MvcHandler相同,因为在一定程度上我们的确只是把原本在MvcHandler里做的事情给提前了:

public class AsyncMvcRouteHandler : IRouteHandler
{
    public IHttpHandler GetHttpHandler(RequestContext requestContext)
    {
        string controllerName = requestContext.RouteData.GetRequiredString("controller");

        var factory = ControllerBuilder.Current.GetControllerFactory();
        var controller = factory.CreateController(requestContext, controllerName);
        if (controller == null)
        {
            throw new InvalidOperationException(...);
        }

        var coreController = controller as Controller;
        if (coreController == null)
        {
            return new SyncMvcHandler(controller, factory, requestContext);
        }
        else
        {

            string actionName = requestContext.RouteData.GetRequiredString("action");
            return IsAsyncAction(coreController, actionName, requestContext) ?
                (IHttpHandler)new AsyncMvcHandler(coreController, factory, requestContext) :
                (IHttpHandler)new SyncMvcHandler(controller, factory, requestContext);
        }
    }

    internal static bool IsAsyncAction(
        Controller controller, string actionName, RequestContext requestContext)
    {
        ...
    }
}

在GetHttpHandler方法中,我们先从RouteData的controller字段中获取控制器的名字,并通过注册在ControllerBuilder上的Factory来创建一个实现了IController接口的控制器对象。由于我们需要使用Controller类中包含的ActionInvoker来辅助检测Action的异步需求,因此我们会设法将其转化为Controller类型。如果转换成功,就会取出RouteData中的action字段的值,并通过IsAsyncAction方法来确认当前Action是否应该异步执行。如果是,则返回一个实现了IHttpAsyncHandler的AsyncMvcHandler对象,否则就返回一个实现IHttpHandler的SyncMvcHandler对象。

至于AsyncMvcRouteHandler的使用,只需在MapRoute时将Route Handler重新设置一下即可:

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    routes.MapRoute(
        "Default",                                              // Route name
        "{controller}/{action}/{id}",                           // URL with parameters
        new { controller = "Home", action = "Index", id = "" }  // Parameter defaults
    ).RouteHandler = new AsyncMvcRouteHandler();
}

检查是否为异步Action

从上面的代码中我们已经形成了一个约定:如果要执行一个异步Action,那么控制器对象必须为Controller类型。这个约定的目的是为了使用Controller类中包含的IActionInvoker——确切地说,是ControllerActionInvoker类型里的功能。因此,另一个约定便是Controller的ActionInvoker对象必须返回一个ControllerActionInvoker的实例。

ControllerActionInvoker中有一些辅助方法,能够返回对于一个Controller或Action的描述对象。从一个Action描述对象中我们可以获取关于这个Action的各种信息,而它是否被标记了AsyncActionAttribute,就是我们判断这个Action是否应该被异步执行的依据。如下:

private static object s_methodInvokerMutex = new object();
private static MethodInvoker s_controllerDescriptorGetter;

internal static bool IsAsyncAction(
    Controller controller, string actionName, RequestContext requestContext)
{
    var actionInvoker = controller.ActionInvoker as ControllerActionInvoker;
    if (actionInvoker == null) return false;

    if (s_controllerDescriptorGetter == null)
    {
        lock (s_methodInvokerMutex)
        {
            if (s_controllerDescriptorGetter == null)
            {
                BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.NonPublic;
                MethodInfo method = typeof(ControllerActionInvoker).GetMethod(
                    "GetControllerDescriptor", bindingFlags);
                s_controllerDescriptorGetter = new MethodInvoker(method);
            }
        }
    }

    var controllerContext = new ControllerContext(requestContext, controller);
    var controllerDescriptor = (ControllerDescriptor)s_controllerDescriptorGetter.Invoke(
        actionInvoker, controllerContext);
    var actionDescriptor = controllerDescriptor.FindAction(controllerContext, actionName);
    return actionDescriptor == null ? false :
        actionDescriptor.GetCustomAttributes(typeof(AsyncActionAttribute), false).Any();
}

ControllerActionInvoker类型中有个protected方法GetControllerDescriptor,它接受一个ControllerContext类型的参数,并返回一个ControllerDescriptor对象来描述当前控制器,而从该描述对象中可以通过FindAction方法获得一个ActionDescriptor对象来描述即将执行的Action。如果是一个不存在的Action,那么就返回false,最后就通过SyncMvcHandler对象来执行默认的行为。当且仅当该Action上拥有AsyncActionAttribute标记时,才说明它应该被异步执行,返回true。此外,这段代码中用到了MethodInvoker,这是一个辅助类,它来源于Fast Reflection Library,它实现了反射调用功能,但是它的性能十分接近于方法的直接调用,我在这篇文章中详细描述了这个项目的功能和使用。

这段代码便涉及到ASP.NET MVC RC版本在Beta版本基础上的改进。在原先的ControllerActionInvoker类中只有获取Action方法的MethodInfo,而没有RC中各描述对象这样的抽象类型。从目前的设计上来看,我们使用的都是基于反射的抽象描述类型的子类。例如默认情况下,我们通过ActionDescriptor抽象类型访问的实际上是ReflectedActionDescriptor类型的实例。这是一个很有用的改进,由于我们通过描述对象进行抽象,于是我们就可以:

  • 使用不同的实现方式来描述各对象,默认情况下是使用基于反射(也就是“约定”)的实现,如果需要的话我们也可以使用基于配置文件的方式替换现有实现。
  • 使用特定对象的描述方式可以不拘泥于内部细节,例如一个异步的Action可能就由两个方法组成。
  • 有了特定的描述对象,也方便添加额外的属性,例如该Action是否应该异步执行,是否应该禁用Session State等等。
  • ……

相关文章

Creative Commons License

本文基于署名 2.5 中国大陆许可协议发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名赵劼(包含链接),具体操作方式可参考此处。如您有任何疑问或者授权方面的协商,请给我留言

Add your comment

43 条回复

  1. 小狼壮壮
    *.*.*.*
    链接

    小狼壮壮 2009-02-02 09:23:00

    沙发,老赵最近心情好阿,笔耕不辍,博客园的福音

  2. 老赵
    admin
    链接

    老赵 2009-02-02 09:30:00

    @小狼壮壮
    心情好?不好啊,没有创意。

  3. 周行天下
    *.*.*.*
    链接

    周行天下 2009-02-02 09:42:00

    你哪里来的那么多的精力哦。佩服。

  4. 文明的天空
    *.*.*.*
    链接

    文明的天空 2009-02-02 09:47:00

    请教赵哥一个问题:
    int Num;
    for(int i=0;i<100;i++){
    Num = ....
    }

    for(int i=0;i<100;i++){
    int Num = ....
    }
    Num只是在for内部用。
    是不是第一种效率更好一些呀?

  5. 老赵
    admin
    链接

    老赵 2009-02-02 09:49:00

    --引用--------------------------------------------------
    周行天下: 你哪里来的那么多的精力哦。佩服。
    --------------------------------------------------------
    没有精力,累啊……只不过写文章是娱乐活动,消耗体力,放松神经——就像去网吧通宵打游戏一样。

  6. 老赵
    admin
    链接

    老赵 2009-02-02 09:52:00

    --引用--------------------------------------------------
    文明的天空: 请教赵哥一个问题:
    int Num;
    for(int i=0;i&lt;100;i++){
    Num = ....
    }

    for(int i=0;i&lt;100;i++){
    int Num = ....
    }
    Num只是在for内部用。
    是不是第一种效率更好一些呀?
    --------------------------------------------------------
    其实没有任何区别
    理论上如果num放for里面可以在出了for的时候就回收掉num,但是其实编译器完全可以做这样的优化。
    当然我觉得从编程角度来说,变量随用随声明比较好。

  7. 文明的天空
    *.*.*.*
    链接

    文明的天空 2009-02-02 09:55:00

    @Jeffrey Zhao
    谢谢赵哥,困扰了好几年的问题!

  8. 柏科学[未注册用户]
    *.*.*.*
    链接

    柏科学[未注册用户] 2009-02-02 10:17:00

    强烈希望老赵根据最新发布的Asp.net MVC框架整理一套权威性的循序渐进的教材帖在博客园上,让后学者慢慢跟进!
    强烈希望老赵根据最新发布的Asp.net MVC框架整理一套权威性的循序渐进的教材帖在博客园上,让后学者慢慢跟进!
    强烈希望老赵根据最新发布的Asp.net MVC框架整理一套权威性的循序渐进的教材帖在博客园上,让后学者慢慢跟进!
    强烈希望老赵根据最新发布的Asp.net MVC框架整理一套权威性的循序渐进的教材帖在博客园上,让后学者慢慢跟进!
    强烈希望老赵根据最新发布的Asp.net MVC框架整理一套权威性的循序渐进的教材帖在博客园上,让后学者慢慢跟进!
    强烈希望老赵根据最新发布的Asp.net MVC框架整理一套权威性的循序渐进的教材帖在博客园上,让后学者慢慢跟进!
    强烈希望老赵根据最新发布的Asp.net MVC框架整理一套权威性的循序渐进的教材帖在博客园上,让后学者慢慢跟进!
    强烈希望老赵根据最新发布的Asp.net MVC框架整理一套权威性的循序渐进的教材帖在博客园上,让后学者慢慢跟进!

  9. 老赵
    admin
    链接

    老赵 2009-02-02 10:19:00

    --引用--------------------------------------------------
    文明的天空: @Jeffrey Zhao
    谢谢赵哥,困扰了好几年的问题!
    --------------------------------------------------------
    不用被这样的东西困扰吧……还好几年……

  10. 老赵
    admin
    链接

    老赵 2009-02-02 10:19:00

    @柏科学
    RTM了再说吧

  11. wingoo
    *.*.*.*
    链接

    wingoo 2009-02-02 10:20:00

    老赵,现在mvc差不多能用在生产环境了吧?
    打算跟进了

  12. TEST1[未注册用户]
    *.*.*.*
    链接

    TEST1[未注册用户] 2009-02-02 10:21:00

    异步请求处理是ASP.NET 2.0中引入的高级特性,它依托IO Complete Port。
    我觉IIS的基层网络处理应该应用了这样的特性,我们在应用层再基于异步扩展性能上真的有所提高?

  13. 生鱼片
    *.*.*.*
    链接

    生鱼片 2009-02-02 10:22:00

    按scott的说法,这个月就应该有RTM了

  14. 老赵
    admin
    链接

    老赵 2009-02-02 10:26:00

    --引用--------------------------------------------------
    wingoo: 老赵,现在mvc差不多能用在生产环境了吧?
    打算跟进了
    --------------------------------------------------------
    应该早跟进了,现在可以上production了

  15. 老赵
    admin
    链接

    老赵 2009-02-02 10:29:00

    --引用--------------------------------------------------
    TEST1: 异步请求处理是ASP.NET 2.0中引入的高级特性,它依托IO Complete Port。
    我觉IIS的基层网络处理应该应用了这样的特性,我们在应用层再基于异步扩展性能上真的有所提高?
    --------------------------------------------------------
    不同层面上的东西。
    IIS是个CLR Host,它就算依托IO Complete Port,但是总还是要有东西执行,什么东西执行呢?自然是托管代码,那还是要占用线程。托管代码占用线程也能省,所以用ASP.NET异步处理。
    同样道理,ASP.NET异步处理,省得是ASP.NET里的线程,该做事的地方还是要做事,比如数据库——现在的优势就相当于不用asp.net陪数据库一起等了。

  16. TEST1[未注册用户]
    *.*.*.*
    链接

    TEST1[未注册用户] 2009-02-02 10:48:00

    @Jeffrey Zhao
    即使是异步也是占用线程,只是把工作分担到别的线程上处理;不用主处理线程处理太多的东西占用时间,从而使主线程进早的空出来处理新的。
    实际上CPU资源并不因异步处理而减少到,从一定程度上来说还有增加。

  17. 老赵
    admin
    链接

    老赵 2009-02-02 11:18:00

    @TEST1
    怎么还在纠结……CPU用的多又不是坏事。
    一个最简单的场景:一个数据库服务器和一个web服务器。
    如果同步,web服务器的线程需要等待数据库服务器的线程,web线程不做事了,CPU自然上不去——就好比竞争多的系统,对资源利用率就不好。
    如果异步,web服务器线程可以去做别的,数据库服务器——因为要做事,怎么省得下来。而web线程作的事情更多了,CPU自然占用的多。
    异步的作用本来就是增加吞吐量,不是为了节省CPU资源。

  18. JimLiu
    *.*.*.*
    链接

    JimLiu 2009-02-02 11:18:00

    --引用--------------------------------------------------
    Jeffrey Zhao: 其实没有任何区别
    理论上如果num放for里面可以在出了for的时候就回收掉num,但是其实编译器完全可以做这样的优化。
    当然我觉得从编程角度来说,变量随用随声明比较好。
    --------------------------------------------------------
    对,而且num是值类型,是在栈上申请空间的,栈本来就属于程序的内存,分配空间不用向系统询问,几乎不消耗时间。
    在C++里用int a[10000];和int* a = new int[10000];速度有本质差别,就是因为前者分配栈内存,后者分配堆内存,需要向系统神奇。

  19. 老赵
    admin
    链接

    老赵 2009-02-02 11:20:00

    @JimLiu
    怎么谈到C++了——C#里的数组也是分配在堆上的啊。

  20. TEST1[未注册用户]
    *.*.*.*
    链接

    TEST1[未注册用户] 2009-02-02 11:39:00

    @Jeffrey Zhao
    所以特定的应用也是分场景的,如果服务器资源并不充足试图用这种方式来提高并发处理不太现实。
    当功能不是分布调用,而又在有限的资源下处理不我感觉不异不比异步好。

  21. Activenetwork
    *.*.*.*
    链接

    Activenetwork 2009-02-02 12:16:00

    老赵终于把你在TechEd上卖的关子兑现了。

    顺便问一句,目前Renew的RC版本依然还是MS Pre Release协议,所以还是不能在自己开发的产品中打包(不管是完整的安装包还是仅仅那3个DLL)。依照你的经验,1.0 Release会和.net fw一样,允许可再分发吗?这个对于产品开发选型很重要。

  22. 老赵
    admin
    链接

    老赵 2009-02-02 12:19:00

    @Activenetwork
    不清楚啊

  23. 老赵
    admin
    链接

    老赵 2009-02-02 12:19:00

    @TEST1
    嗯,肯定要根据情况来,但是我觉得适合异步的情况基本上很普遍,因为普通handle一个请求需要的资源很少,一般来说总能获利。当然IOCP和异步也不是没有代价,因此在极端场景下的确可能无效。简单地说,它不是为了从0到1的,而是为了从1到2的。
    不过这一点和是否分布无关,因为系统线程和应用程序中的线程也是两码事。

  24. 阿牛
    *.*.*.*
    链接

    阿牛 2009-02-02 13:26:00

    --引用--------------------------------------------------
    文明的天空: 请教赵哥一个问题:
    int Num;
    for(int i=0;i&lt;100;i++){
    Num = ....
    }

    for(int i=0;i&lt;100;i++){
    int Num = ....
    }
    Num只是在for内部用。
    是不是第一种效率更好一些呀?

    --------------------------------------------------------
    for(int i=0;i&lt;100;++i)

    效率高

  25. 重典
    *.*.*.*
    链接

    重典 2009-02-02 13:45:00

    异步来解决问题还是不错的.老赵真是精力十足啊,我已经48小时没睡了.....

    想起RC的MvcFutures有AsyncController,不过还没有看,不知道是不是差不多的

  26. 老赵
    admin
    链接

    老赵 2009-02-02 13:58:00

    @阿牛
    没必要的,编译以后一样。

  27. 老赵
    admin
    链接

    老赵 2009-02-02 13:59:00

    @重典
    完全不一样,当然我对它的设计存疑

  28. xjb
    *.*.*.*
    链接

    xjb 2009-02-02 15:41:00

    老赵最近很勤奋呀

  29. andy.wu
    *.*.*.*
    链接

    andy.wu 2009-02-02 16:06:00

    对异步使用不熟悉,在此有个疑问。

    ms的异步支持模式看似很广泛,ado.net,asp.net等等中都能发现。举个简单的场景,如果用了异步的handler,是否在大多数情况下就没必要再用异步的ado.net调用了。也就是说多种异步调用不应该组合在一起。


  30. 老赵
    admin
    链接

    老赵 2009-02-02 19:56:00

    @andy.wu
    恰恰相反,对于异步handler调用,也只有配合其他异步操作才有效果。原因你可以思考一下,呵呵。

  31. andy.wu
    *.*.*.*
    链接

    andy.wu 2009-02-02 21:22:00

    --引用--------------------------------------------------
    Jeffrey Zhao: @andy.wu
    恰恰相反,对于异步handler调用,也只有配合其他异步操作才有效果。原因你可以思考一下,呵呵。
    --------------------------------------------------------

    我刚才是想错了,把客户端和服务端的异步混淆了。

    对于异步handler来说,只是提高了服务器端的负载能力,而对客户端来说是没什么变化,该是10秒还是10秒。应该是这样理解的吧。

    但如果这样理解的话,那么服务器的socket负载应该没什么改进,比如iis的socket连接上限为100,即使服务器的运算性能通过异步方式可以支持200个同时连接,在这种情况下,依然只能达到100了。

  32. 老赵
    admin
    链接

    老赵 2009-02-02 23:40:00

    @andy.wu
    嗯,可能是,但是socket负载远达不到。
    而且如果和之前有个朋友说的,iis也用了iocp,那么我想这个连接上限就更加达不到了。

  33. 周行天下
    *.*.*.*
    链接

    周行天下 2009-02-03 09:58:00

    --引用--------------------------------------------------
    Jeffrey Zhao: --引用--------------------------------------------------
    周行天下: 你哪里来的那么多的精力哦。佩服。
    --------------------------------------------------------
    没有精力,累啊……只不过写文章是娱乐活动,消耗体力,放松神经——就像去网吧通宵打游戏一样。
    --------------------------------------------------------
    我永远也比不上你了。唉,人和人的差距为什么会这么打。

  34. 妖居
    *.*.*.*
    链接

    妖居 2009-02-03 12:33:00

    老赵终于把TechED上说的问题解决了:)

  35. 文明的天空
    *.*.*.*
    链接

    文明的天空 2009-02-03 14:15:00

    --引用--------------------------------------------------
    Jeffrey Zhao: --引用--------------------------------------------------
    文明的天空: @Jeffrey Zhao
    谢谢赵哥,困扰了好几年的问题!
    --------------------------------------------------------
    不用被这样的东西困扰吧……还好几年……
    --------------------------------------------------------
    呵呵,有两方面的原因
    1.我比较笨.
    2.我没用心.
    赵哥说的是!

  36. james-brook[未注册用户]
    *.*.*.*
    链接

    james-brook[未注册用户] 2009-02-04 14:39:00

    呵呵!准备学习MVC。

  37. 李晓强
    *.*.*.*
    链接

    李晓强 2009-02-18 14:09:00

    ASP.NET MVC 中,如果母版页中有一些控制逻辑,比如说母版页要访问数据库动态的生成一个(导航)树.这个动作应该怎么实现?好像一个view不可以对应多个Action吧.

  38. 老赵
    admin
    链接

    老赵 2009-02-18 14:11:00

    --引用--------------------------------------------------
    李晓强: ASP.NET MVC 中,如果母版页中有一些控制逻辑,比如说母版页要访问数据库动态的生成一个(导航)树.这个动作应该怎么实现?好像一个view不可以对应多个Action吧.
    --------------------------------------------------------
    什么叫做一个View对应多个Action?

  39. ITAres
    *.*.*.*
    链接

    ITAres 2009-02-25 18:46:00

    我没发现这样做有什么好处?


    好像用户请求等待的时间跟同步处理是一样的...


    老赵可以说说这样做的优点在什么地方吗?主要解决了什么问题?

  40. 没剑
    *.*.*.*
    链接

    没剑 2009-03-09 14:51:00

    老赵,可以给个完整的异步的例子吗????期待

  41. 老赵
    admin
    链接

    老赵 2009-03-09 14:56:00

    @没剑
    (下)最后有。

  42. axers
    *.*.*.*
    链接

    axers 2009-04-09 19:12:00

    --引用--------------------------------------------------
    Jeffrey Zhao: --引用--------------------------------------------------
    文明的天空: 请教赵哥一个问题:
    int Num;
    for(int i=0;i&amp;lt;100;i++){
    Num = ....
    }

    for(int i=0;i&amp;lt;100;i++){
    int Num = ....
    }
    Num只是在for内部用。
    是不是第一种效率更好一些呀?
    --------------------------------------------------------
    其实没有任何区别
    理论上如果num放for里面可以在出了for的时候就回收掉num,但是其实编译器完全可以做这样的优化。
    当然我觉得从编程角度来说,变量随用随声明比较好。
    --------------------------------------------------------

    对值类型没有区别,但如果声明的是引用类型就会有较大影响了吧?我觉养成习惯还是放外面比较好,如果是引用类型在for内部声明就只能等GC来回收了吧

  43. Jeffrey Zhao
    *.*.*.*
    链接

    Jeffrey Zhao 2009-04-10 09:09:00

    @axers
    注意概念。为一个引用创建n个对象难道就节省空间了吗?

发表回复

登录 / 登录并记住我 ,登陆后便可删除或修改已发表的评论 (请注意保留评论内容)

昵称:(必填)

邮箱:(必填,仅用于Gavatar

主页:(可选)

评论内容(大于5个字符):

  1. Your Name yyyy-MM-dd HH:mm:ss

使用Live Messenger联系我