none
ashx IsReUseable 问题 RRS feed

  • 问题

  • 请教关于ashx属性的问题.

    关于IsReUseable的属性的解释,看到了这样一篇文章

    http://www.cnblogs.com/TomXu/archive/2011/12/17/2288579.html

    里面说到线程安全,不太理解.

    比如我利用ashx进行一般的增删改查操作,会涉及到线程安全吗.

    例如

    string userName=Request["UserName"];

    string userPwd=Request["UserPwd"];

    数据库操作,AddUser(userName,userPwd);

    象这样的操作,会有线程安全的问题么.

    如果设置IsReUseable=true

    当ashx处理第一个用户发送来的数据时,接收了他的userName,userPwd,

    然后申请数据库连接,还未插入数据的时候,接收到第二个用户发送来的数据,那么,第二个用户发来的数据会不会覆盖了第一个用户的数据.

    导致最后插入的是第二个用户发送过来的数据,而第一个用户的操作实际没有完成.

    2013年1月16日 13:26

答案

  • IsReUseable是用来标识当前IHttpHandler实例是否可以被重用的。

    如果设置为 False,请求A和请求B就会使用两个IHttpHandler实例;

    如果设置为 True,请求A和请求B就可以共用同一个IHttpHandler实例;

    因此当 IsReUseable 设置为 True 时,如果 IHttpHandler 实例的成员是可以共享的,那么就是线程安全的,如果不是共享的,那么就需要对成员做线程安全保护。

    单从你给的代码来看,设置为 True 或 False,都没什么影响。

    我提供一个简单的例子,事实上你也可以写这么个例子来理解文字的含义:

    class QHttpHandler : IHttpHandler

    {

        private int _objCount =0;

       void ProcessRequest()

    {

    Interlocked.Increment(ref _objCount);

    }

    }

    IsReuseable 为 False 时,两次请求后,会创建两个 QHttpHandler 对象,并且它们的 _objCount 都是 1。

    IsReuseable 为 True 时,两次请求后, 只会创建一个 QHttpHandler 对象,并且它的 _objCount 是 2。

    • 已标记为答案 httpmms 2013年1月18日 4:46
    2013年1月17日 8:48

全部回复

  • IsReUseable是用来标识当前IHttpHandler实例是否可以被重用的。

    如果设置为 False,请求A和请求B就会使用两个IHttpHandler实例;

    如果设置为 True,请求A和请求B就可以共用同一个IHttpHandler实例;

    因此当 IsReUseable 设置为 True 时,如果 IHttpHandler 实例的成员是可以共享的,那么就是线程安全的,如果不是共享的,那么就需要对成员做线程安全保护。

    单从你给的代码来看,设置为 True 或 False,都没什么影响。

    我提供一个简单的例子,事实上你也可以写这么个例子来理解文字的含义:

    class QHttpHandler : IHttpHandler

    {

        private int _objCount =0;

       void ProcessRequest()

    {

    Interlocked.Increment(ref _objCount);

    }

    }

    IsReuseable 为 False 时,两次请求后,会创建两个 QHttpHandler 对象,并且它们的 _objCount 都是 1。

    IsReuseable 为 True 时,两次请求后, 只会创建一个 QHttpHandler 对象,并且它的 _objCount 是 2。

    • 已标记为答案 httpmms 2013年1月18日 4:46
    2013年1月17日 8:48
  • 感谢您的回复.您的说法,我能接受.但文章中有这么一段话让我迷惑.

    另外,由于HttpHandler实例是由HttpHandlerFactory来创建的,而HttpHandlerFactory创建HttpHandler实例的时候会将上下文信息HttpContext作为参数传进去,如果多个工作者线程共享这个实例的话,那就不能都依赖HttpContext.Request内容,因为依赖了,那各个请求就乱了,比如你通过一个Request参数设置Httphandler的一个属性值,然后其他线程在调用的时候就有可能用到这个值,(但是可以利用Request参数去分别处理自己的逻辑,只要不共享就行),再比如我们如果在做多用户信息的时候,如果一个用户能管理另外一个用户的资源的话,那就有问题了。

    特别是这句:如果多个工作者线程共享这个实例的话,那就不能都依赖HttpContext.Request内容

    所以我才迷惑,当我们接收Request["UserName"]时,这个值是否会被后来者改变.
    我理解的是,只要不用到可写的全局变量或可写的静态变量,应该就不会有问题.
    public void ProcessRequest (HttpContext context)中,context是非静态的,所以不会有问题.
    但我还有一点担心,因为HttpContext.Current是静态的.那么
     ProcessRequest (HttpContext context)中的context真的是new 出来的吗?
    基本功没学好,可能有些混乱,望见谅.

    2013年1月17日 9:38
  • 感谢您的回复.您的说法,我能接受.但文章中有这么一段话让我迷惑.

    另外,由于HttpHandler实例是由HttpHandlerFactory来创建的,而HttpHandlerFactory创建HttpHandler实例的时候会将上下文信息HttpContext作为参数传进去,如果多个工作者线程共享这个实例的话,那就不能都依赖HttpContext.Request内容,因为依赖了,那各个请求就乱了,比如你通过一个Request参数设置Httphandler的一个属性值,然后其他线程在调用的时候就有可能用到这个值,(但是可以利用Request参数去分别处理自己的逻辑,只要不共享就行),再比如我们如果在做多用户信息的时候,如果一个用户能管理另外一个用户的资源的话,那就有问题了。

    特别是这句:如果多个工作者线程共享这个实例的话,那就不能都依赖HttpContext.Request内容

    所以我才迷惑,当我们接收Request["UserName"]时,这个值是否会被后来者改变.
    我理解的是,只要不用到可写的全局变量或可写的静态变量,应该就不会有问题.
    public void ProcessRequest (HttpContext context)中,context是非静态的,所以不会有问题.
    但我还有一点担心,因为HttpContext.Current是静态的.那么
     ProcessRequest (HttpContext context)中的context真的是new 出来的吗?
    基本功没学好,可能有些混乱,望见谅.

    你疑惑,是因为你没看明白它所指的“依赖”的具体含义,例如:

    void ProcessRequest (
    HttpContext context)

    {

       string name = context.Request["UserName"];

    }

    这不应该被理解为 HttpHandler 实例“依赖” context,因为入参 context 只是一个临时引用,name 也只是一个临时变量,超出了 ProcessRequest 作用域后,它们就被释放了。

    private string _name;

    void ProcessRequest (
    HttpContext context)

    {

       this._name = context.Request["UserName"];

    }

    上面的代码才能叫着“依赖”,因为超出作用域后,HttpHandler 实例还保留了 context 指定的状态值(UserName),如果HttpHandler被多个请求上下文共享,那么就会造成 _name 值的不确定性,也就不能以 _name 的值来确定对象的状态。当然,如果你这里只是这一句代码的话,事实上 IsReuseable 被设置为 True 或 False 都没有关系,都不影响程序的正常逻辑。

    "因为依赖了,那各个请求就乱了,比如你通过一个Request参数设置Httphandler的一个属性值,然后其他线程在调用的时候就有可能用到这个值,(但是可以利用Request参数去分别处理自己的逻辑,只要不共享就行)"

    因此,具体的问题还要具体分析,关键不是看别人怎么描述的,而是你自己要明白代码的逻辑。

    同样对于你的疑问,最好的方式仍然是通过代码来测试,你可以检测入参 context 和 HttpContext.Current 是否总是为同一个对象。事实上我也不是很清楚,但是我知道它必定是其中的一种:1、如果 ProcessRequest 是并行运行的,那么 HttpContext.Current 不会总是和 context 相等;2、如果 ProcessRequest 是串行执行的,那么 HttpContext.Current 总是和 context 相等。

    2013年1月18日 1:48
  • 这个问题,msdn上也找不到合适的说法,代码测试,恐怕因为个人认知的局限,得出的结论恐怕也未必完全正确.
    但,对于设置为false,总是安全的,至于性能.

    我们一般的Page类,他实现了IHttpHandler接口,而IsReUseable的值总是false
    http://msdn.microsoft.com/zh-cn/library/system.web.ui.page.isreusable(v=vs.80).aspx

    所以ashx的性能总是比aspx高,也不像网上说的开销大,让我们有些恐惧而不太敢使用.因为既然我们能接受aspx,那么应该更能接受ashx,即使他的IsReUseable设为false

    2013年1月18日 4:46
  • 这个问题,msdn上也找不到合适的说法,代码测试,恐怕因为个人认知的局限,得出的结论恐怕也未必完全正确.
    但,对于设置为false,总是安全的,至于性能.

    我们一般的Page类,他实现了IHttpHandler接口,而IsReUseable的值总是false
    http://msdn.microsoft.com/zh-cn/library/system.web.ui.page.isreusable(v=vs.80).aspx

    所以ashx的性能总是比aspx高,也不像网上说的开销大,让我们有些恐惧而不太敢使用.因为既然我们能接受aspx,那么应该更能接受ashx,即使他的IsReUseable设为false

    测试的结果才是最正确的,也就是说我们经常说的“别听他吹的天花乱坠,其实不是那么回儿事”;因此,就算你的软件的开发文档写的再好,你的设计写的再详细,也要通过全面的测试才能证明软件的可靠性。

    开销大不大,关键看你要实现什么,比如如果我想共享一些状态,我就可以通过这个机制来避免增加额外的类来管理单一实例。

    2013年1月18日 5:23