http://www.sufeinet.com/plugin.php?id=keke_group

苏飞论坛

 找回密码
 马上注册

QQ登录

只需一步,快速开始

分布式系统框架(V2.0) 轻松承载百亿数据,千万流量!讨论专区 - 源码下载 - 官方教程

HttpHelper爬虫框架(V2.7-含.netcore) HttpHelper官方出品,爬虫框架讨论区 - 源码下载 - 在线测试和代码生成

HttpHelper爬虫类(V2.0) 开源的爬虫类,支持多种模式和属性 源码 - 代码生成器 - 讨论区 - 教程- 例子

查看: 11176|回复: 8

[Asp.Net] 网站[高并发]下使用[静态方法]会造成页面无法访问的解决方案

[复制链接]
发表于 2013-7-17 18:25:12 | 显示全部楼层 |阅读模式
先来说明一下问题,2楼开始说解决方案
委托delegate与Dictionary实现action选择器大家先看看我上一次的文章
大致如下
[C#] 纯文本查看 复制代码
//定义一个委托
   private delegate void actionByMain(HttpContext context);
   //定义一Key,Value的键值对,大家注意这里把委托放进去了
   private static Dictionary<string, actionByMain> mainList = new Dictionary<string, actionByMain>();
   public void ProcessRequest(HttpContext context)
   {
       string action = string.Empty;
       if (string.IsNullOrEmpty(context.Request["action"]))
       {
           return;
       }
       action = context.Request["action"];
       //先检查一下有没有这个action
       if (mainList.ContainsKey(action))
       {
           mainList[action](context); return;
       }
   }
   //添加action对应方法的列表
   static void addMainList()
   {
       mainList.Add("post1", delegate(HttpContext context)
      {
          context.Response.Write("成功");
      });
       mainList.Add("post2", delegate(HttpContext context)
     {
         context.Response.Write("成功");
     });
       mainList.Add("post3", delegate(HttpContext context)
     {
         return;
     });
   }

就是这样的写法,容易出现问题
在高并发的时候经常出现页面无法访问的问题
其实我也不敢确定是不是这里的问题但是有以下几点可以确定
可能会有人说,如果不使用这种而是直接调用静态方法呢,是一样的效果。这点我测试过。
第一点换成普通类型


换成如下写法就不会出现这样的问题
[C#] 纯文本查看 复制代码
//取出action的值
string action = context.Request["action"];
if (action == "post1")
{
   //调用第一个Post方法
}
else if (action == "post2")
{
   //调用第一个Post方法
}
else if (action == "post3")
{
   //调用第一个Post方法
}
else
{
   //调用在没有找到action对应方法时执行
}[/code]
方法如下
[mw_shl_code=csharp,true] private void post1()
{

}
private void post2()
{

}
private void post3()
{

}

第二点:访问量比较小时,本页面日访问量低于2万Pv的就不要测试了,应该不会有效果


   这个我经过测试确定是这样的
第三点:IIS设置应用程序池不回收时,也不会出现这样的问题,但是只要设置回收就会出现

这一点虽然我不知道是什么情况但是实际效果就是这样
总结:
这个问题一直得不到一个完整合理的解释,希望博客园的高手们进来看看,帮助解释一下是什么问题造成的。
我的理解:
     我认为会不会是因为正好在高并发的时候IIS开始回收,在回收时或者是在页面重建时,就在这一刻是无法访问的,而且正好让用户访问了,而这个状态正好被浏览器记录了下来,然后就不能访问了,
第四点:因为经过我们的测试,只要清理一下浏览器的缓存或者是重启电脑路由之后就基本上又可以正常访问了
这种现像很难解释啊,
所以没有办法后来我又修改成了。普通的写法。
大家讨论一下看看具体是那里的问题
我确实是解释不了这种现像了。


1. 开通SVIP会员,免费下载本站所有源码,不限次数据,不限时间
2. 加官方QQ群,加官方微信群获取更多资源和帮助
3. 找站长苏飞做网站、商城、CRM、小程序、App、爬虫相关、项目外包等点这里
 楼主| 发表于 2013-7-17 18:25:43 | 显示全部楼层
[code=csharp]addMainList()是在什么地方调用的?构造函数?mainList是static的非线程安全的dictionary,增删改mainList的时候要加锁! 你这个例子,最简单的是把addMainList()放到静态构造函数里面调用 static ClassName
(){addMainList();}
或者增删改mainList的时候加锁
static object LockObj=new object();
static void addMainList()
{
lock(LockObj)
{
mainList.Add("post1", delegate(HttpContext context)
{
context.Response.Write("成功");
});
mainList.Add("post2", delegate(HttpContext context)
{
context.Response.Write("成功");
});
mainList.Add("post3", delegate(HttpContext context)
{
return;
});
}
}[/code]
 楼主| 发表于 2013-7-17 18:25:56 | 显示全部楼层
高并发的时候才出问题,那是因为高并发的时候会出现多个线程同时操作mainList, 由于它不是线程安全的,所以就报错了! 加锁就是为了限制在一个线程操作它的时候,其他线程等待它操作完了再对它操作!
你这个mainList其实是很简单的字典而已,其实不要把它声明为static就不会有线程的安全问题!很多方法可以处理的,看你需要怎么用而已
 楼主| 发表于 2013-7-17 18:26:04 | 显示全部楼层
基本上可以判断是多线程冲突导致,你列举的几点都很符合多线程冲突场景。
第四点的话,可能是浏览器接收到IIS返回的错误信息,导致浏览器缓存了一些错误信息。具体问题,还需要你具体说明一下浏览器无法访问的错误信息。

static void addMainList() 这个方法是什么时候调用的?至少看起来不是静态构造函数,所以没有加锁的话,应该是会导致错误的。

if (mainList.ContainsKey(action))
       {
           mainList[action](context); return;
       }
mainList 应该不会因为回收导致为null,只要这个类还在运行,是不会回收的。但Dictionary本身不是线程安全的,所以这个用法有错。Dictionary的读写都不是线程安全的,包括ContainsKey方法。
 楼主| 发表于 2013-7-17 18:32:28 | 显示全部楼层
我们说一个数据结构是线程安全指的是同一时间只有一个线程可以改写它。这样即使多个线程来访问它,它也不会产生对线程来说很意外的数据。
C#中的Dictionary不是线程安全的,我在下面这个例子中,把一个Dictionary对象作为了全局的static变量。会有多个线程来访问它。所以我需要包装一下.net自带的Dictionrary.
发生冲突的部分无非是写的地方,所以在离写Dictionary最近的地方加一个锁。其他的外层代码可以自带的Dictionary相同了。
我们看Dictionary的实现接口,

SafeDictionary.JPG
syncRoot是自定义SafteDictionary内的互斥对象,哪个线程拿到它才可以对内部的Dictionary进行操作。
比如new Dictionary().Add加一个syncRoot的锁,变成
     [code=csharp]   public void Add(TKey key, TValue value)
        {
            lock (syncRoot)
            {
                d.Add(key, value);
            }
        }[/code]
   同一个时间点只能有一个线程能够访问d.Add(key, value);

   定义一个全局的SafeDictionray对象,则它不会同时被多个线程操作。
   附件中的例子中定义了一个全局的SafeDictionray对象Helper.DicNetStatus,表示IP地址对应设备的连接状态,IP为Key,True/False为Value,在程序启动时有一个DealingData线程不停的在刷新Helper.DicNetStatus的值,每隔1秒刷一次。MainForm是主界面线程。另外有一个MainForm的后台线程DisplayDicStatus不停的在读取Helper.DicNetStatus的值,每隔1秒刷一次,刷一次就反映到界面上来,可以显示出某个IP设备的连接状态。就像QQ列表中根据不同头像显示好友的不同连线状态一样。
   总结一下附件例子中涉及到的知识点:
   1,如果解决多线程操作某个全局数据对象的问题。解决方法:自定义一个线程安全的数据对象类。
   2,如何跨线程调用界面控件。解决方法:this.Invoke(设置界面控件的代理)

 楼主| 发表于 2013-7-18 08:37:08 | 显示全部楼层
[C#] 纯文本查看 复制代码
private static readonly object @lock = new Object();

public void ProcessRequest(HttpContext context)
   {
       string action = string.Empty;
       if (string.IsNullOrEmpty(context.Request["action"]))
       {
           return;
       }
       action = context.Request["action"];

       lock(@lock)
       {
       //先检查一下有没有这个action
       if (mainList.ContainsKey(action))
       {
           mainList[action](context); return;
       }
       }
   }

   //添加action对应方法的列表
   static void addMainList()
   {
     lock(@lock)
     {
       if(mainList.Count > 0)
       {
           return;
       }
       mainList.Add("post1", delegate(HttpContext context)
      {
          context.Response.Write("成功");
      });
       mainList.Add("post2", delegate(HttpContext context)
     {
         context.Response.Write("成功");
     });
       mainList.Add("post3", delegate(HttpContext context)
     {
         return;
     });
     }
   }

可以这样加锁,不过这样的效率很差。建议你采用无锁方案,比如ConcurrentDictionary
可以参考这里http://www.cnblogs.com/lulu/archive/2012/05/26/2519675.html

 楼主| 发表于 2013-7-18 10:19:06 | 显示全部楼层
ConcurrentDictionary<TKey, TValue> 类

表示可由多个线程同时访问键/值对线程安全集合对。
发表于 2013-7-23 00:51:58 | 显示全部楼层
你出现的情况 正好我也测试到了 ,  服务器上访问是活得,  客户端浏览器不能访问 。
你得第四点 我还没有实验 。
 楼主| 发表于 2013-8-12 09:09:35 | 显示全部楼层
Dictionary本来就是不安全的,用静态,这不是火上加油么。看看这个吧,ConcurrentDictionary<TKey, TValue> 类

表示可由多个线程同时访问键/值对线程安全集合对。
您需要登录后才可以回帖 登录 | 马上注册

本版积分规则

QQ|手机版|小黑屋|手机版|联系我们|关于我们|广告合作|苏飞论坛 ( 豫ICP备18043678号-2)

GMT+8, 2024-5-6 05:45

© 2014-2021

快速回复 返回顶部 返回列表