posts - 6,  comments - 25,  trackbacks - 1
在多线程编程中,很多地方都会碰到同时操作一个全局变量的问题,我们在操作过程中应该怎么避免发生混乱呢?

分下面几个方面讨论:

从变量的特点上分,可以分为简单对象的安全问题和集合对象的安全问题。简单对象只要使用lock关键字就可以解决问题,这里主要讨论集合对象的安全问题。

集合对象一般我们使用较多的有键值对的集合,如:字典,哈希表等,一般都会有key ---value对。

这里举个最简单的例子:我们在很多地方可以看到操作webCache缓存的代码,如下;
1public MyObject Get(String key)
2{
3    MyObject o;
4    if(CacheHelper[key]==null){
5      o=从数据库或者其他数据源获取o对象;
6      CacheHelper.Insert(key,o,..........
7    }

8    return o;
9}
上面代码貌似比较好的解决了缓存问题,但是确存在着效率浪费的问题。(假设上面的缓存内容是某个论坛的帖子)

当你网站的同时访问量够大,够多的时候,而第5行的运行需要一些时间的时候,可能发生,应用程序刚启动的时候,对于同一个key,有上百个人会同时来运行到第3行,此时上百个人判断出key的结果是null,此时全部一起去运行第5行(事实上对于同一个key,我们要让它只运行一次第5行)。

这个过程就是个很浪费效率的过程。

此时有人可能会问:“那我们在加载数据的时候锁不就得了”,看下面代码就是加锁的代码
 1private static object lockhelp=new object();
 2
 3public MyObject Get(String key)
 4{
 5    MyObject o;
 6    if(CacheHelper[key]==null){
 7      lock(lockhelp){
 8        if(CacheHelper[key]==null){
 9          o=从数据库或者其他数据源获取o对象;
10          CacheHelper.Insert(key,o,.
11        }

12      }

13    }

14    return o;
15}
此时确实是解决了一个对象只被加载一次,不过确发生了更糟糕的问题。

服务器刚启动的时候,当n个人来运行的时候,无论来的是哪个key,都会导致阻赛等待,如果同时有3000人来访问,保证你的服务器挂机。

那么我们怎么解决这个问题呢。

我们可以..... 待续.....待续

还没写完呢,就看到赵兄在评论了。不错,赵兄的方法正解。要解决问题的方法还是比较简单的,主要问题是很多兄弟一下次眼昏没有注意到这个问题。

不过从完整的解决上来说,应该是新建一个字典,字典中key就是我们外面的key,字典中的value是我们的lockhelp,在读取之初,new一个lockhelp到字典中,然后加锁开始读取数据,而当字典中有这个key的lockhelp时,直接拿出来lock住。
==========================================================================
这种方法:赵兄在3楼有所点评,赵兄的意思是如果同时操作的key过多,会产生大批量的锁。这确实是个问题。
如果我们要做如上方式缓存,一般情况下是对所有传进来的Key的相同率较高才会使用。如果key传进来基本上不一样,那么用上面这种缓存策略意义不是很大。如:论坛帖子,再热门的论坛我看也就最新的几篇,最热门的几篇,最精华的几篇的id传进来概率大。所以说,上面的缓存策略应用环境是针对key相同匹配率较高的环境,此时lockhelp不会出现超大的情况,毕竟我提出的问题是发生在 应用程序刚刚启动的时候,如果进入正常运行了是不会有这个问题的。

而针对key情况超大的时候,我们不是很必要用上面的缓存方法。key超大,说明缓存内容的差异性超大,每个人来访问的内容都会不一样。
==========================================================================
对于6楼提出的问题,我想可以用简单的代码示范一下
代码一:
1private static Object o=new Object();
2
3public void MyF(){
4     lock(o){
5       //dosamething
6     }

7}
代码二:
1public void MyF(){
2     Object o=new Object();
3     lock(o){
4       //dosamething
5     }

6}
上面两个代码,代码一 就是n个人进来会阻塞,你认为代码二 n个人进来也会阻塞吗?你可以代码调式一下。
===========================================================================

随着我们应用的越来越复杂,很多不同的情况下对线程安全都要做不同的处理。

如:当我们碰到对集合的更新是整个集合更新,而不是一个key一个key更新,更新频率又比较高,每次都是整个集合更新,这个时候我们又该如何保证我们的线程安全。

此时我们一般是采用在轮询过程中,先从数据库中提取新的集合到临时集合中,然后赋值给使用中的集合。

posted @ 2008-01-25 23:15 狂图 阅读(1600) | 评论 (7)编辑

症状:

对最终用户的需求理解的不够精确
对需求的改变束手无策
程序块不兼容
软件不易维护或不易扩展
对项目严重缺陷的发现较晚
软件质量低劣
软件性能无法令人接受
开发组中的人员按各自的方式进行开发,如果有人改变了部分软件,将很难再进行重组
一个不可靠的构造和发布过程

原因:

特别的需求管理
模糊和不精确的交流
脆弱哦的构架
过度复杂
未检测出需求、设计和实现之间的不一致
测试的不足
对于项目状况的评估过于主观
未解决存在的风险
无法控制变化的产生和传播
自动控制不足

posted @ 2007-04-17 14:11 狂图 阅读(80) | 评论 (0)编辑
     摘要: 各种各式各样的图片缩略水印静态,注释写的不多。慢慢看吧,应该难度不大。
  阅读全文
posted @ 2007-04-14 16:36 狂图 阅读(603) | 评论 (1)编辑

看到很多人在说图片高质量保存的问题,一个图片高质量保存共享一下。

/// <summary>
        /// 高质量保存
        /// </summary>
        /// <param name="image"></param>
        /// <param name="path"></param>
        public static void SaveQuality(Image image, String path)
        {
            ImageCodecInfo myImageCodecInfo;
            Encoder myEncoder;
            EncoderParameter myEncoderParameter;
            EncoderParameters myEncoderParameters;
            myImageCodecInfo = ImageCodecInfo.GetImageEncoders()[0];
            myEncoder = Encoder.Quality;
            myEncoderParameters = new EncoderParameters(1);
            myEncoderParameter = new EncoderParameter(myEncoder, 100L); // 0-100
            myEncoderParameters.Param[0] = myEncoderParameter;
            try
            {
                image.Save(path, myImageCodecInfo, myEncoderParameters);
            }
            finally
            {
                myEncoderParameter.Dispose();
                myEncoderParameters.Dispose();
            }
        }


using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;

posted @ 2007-04-14 14:07 狂图 阅读(480) | 评论 (2)编辑
  1. 在“工具”菜单上单击“Internet 选项”。

  2. 在“Internet 选项”对话框中,单击“高级”选项卡。

  3. 在“浏览”类别中,清除“禁用脚本调试”复选框。

  4. 单击“确定”。

  5. 关闭 Internet Explorer 使该选项生效。

  6. 打开IE,输入你要调试的脚本所在的url

  7. 打开VS2005,选择菜单“工具”-->“附加到进程”

  8. 在窗口中选择你打开的IE的进程,有个“选择”按钮,打开,选择“脚步”。

  9. 确定后,就会在vs里多个“脚本资源管理器”出来,没有的可以在“调试”-->“窗口”-->这里看到,打开

  10. 在“脚本资源管理器”你会看到所有的IE里的页面结构,单击某个js文件,就可以对这个js文件进行断点设置了,

  11. 余下的工作就和普通调试一样了,哈哈

posted @ 2007-04-08 22:20 狂图 阅读(1033) | 评论 (0)编辑

首先是我所作的B/S软件需要多种数据库的支持,其中就包括Access数据库。而为了达到快的速度,必须把access的连接放入数据库连接池,所以我专门给access做了个数据库连接池。

问题出现了:“就是用access连接池的时候,有的时候会出现修改过的数据不能及时的反应到界面上来。”

刚开始我以为是我的access连接池写的有问题,于是是大找特找就是找不到原因,后来我干脆不用池,直接自己new一个全局连接放在静态变量里看一下会不会有问题,结果显示完全没有问题。

接着我又new 了两个连接放在静态变量里  conn1 和  conn2   ,  然后让conn1做了一个update数据操作,conn2又立马获取update的值,结果显示 获取的数据还是update前的数据,  然后过3到5秒 再让conn2去获取update的值 才能看到已经修改了。

于是我得出这样的结论,access数据库的多个连接情况下,其中某一个连接进行了修改操作需要过3到4秒才能反映到其他连接里来

如果这个结论被确定那就是说 access无法实现 传统上的 数据库连接池。

于是我想会不会是我的数据库操作代码有问题,于是我干脆用两台电脑做测试,分别在两台电脑上用office打开同一个access数据库,然后在其中一台上修改了某个数据,另外一台上立马打开改数据,结果显示 数据还是没有更新。  靠。从目前来看我上面的结论是符合实际的。

如果真的这个结论被坐实的话,就像我上面说的,“access无法实现 传统上的 数据库连接池”。那麻烦就大了,因为其他数据库连接池,如:sqlserver,是可以用的,而access不能用,那么可能需要更多的代码区分开来编写。

于是我又想,会不会是使用access连接的时候有没有什么特殊的属性(或者说方式),才能保证多个access连接能及时的反应信息。

哪位达人看到这个问题,如果能解决的给小子回复一下。

qq:54825898
email:chaxcha@gmail.com

这里付上操作数据库的代码:
说明:test.mdb中一个表,test 表,中间有两个自段id  和 num  都是数字。记录就一条 id=1  num=1
protected void LinkButton11_Click(object sender, EventArgs e)
    {
        String connStr = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + Server.MapPath("/test.mdb") + ";Persist Security Info=True;";
        String selectSql = "select [num] from  [test] where [id]=1";
        String updateSql = "Update [test] set [num]=[num]+1 where [id]=1";


        OleDbConnection connForUpdate = new OleDbConnection(connStr);
        OleDbConnection connForSelect = new OleDbConnection(connStr);
       
        OleDbCommand cmd;
        Object resultValue;

        try
        {
            connForUpdate.Open();
            connForSelect.Open();

            //修改前提取
            cmd = new OleDbCommand(selectSql, connForSelect);
            resultValue = cmd.ExecuteScalar();
            Response.Write("修改前:" + resultValue);
            Response.Write("<br/>");

            resultValue = null;

            //执行修改
            cmd = new OleDbCommand(updateSql, connForUpdate);
            cmd.ExecuteNonQuery();

            //修改后提取
            cmd = new OleDbCommand(selectSql, connForSelect);
            resultValue = cmd.ExecuteScalar();
            Response.Write("修改后:" + resultValue);

        }
        finally
        {
            connForSelect.Close();
            connForUpdate.Close();
        }
    }

此代码的结果是:
修改前:6
修改后:6

最终结论是,Access确实不能很好的实现连接池。 没法子,只能是变相的解决问题了。
我这里给出Access操作的几个可以提高速度方法:
1.让某些只是提取操作的单步业务使用同一个链接, 该连接因为都是单步提取数据,所以“不是即时性”的数据问题不大,如:获取点击数、查询等等都使用同一个连接,此conn保持状态不要关闭。
2.如果是非单步的业务就要使用完了连接及时关闭,不然会出现看不到刚刚更新过的数据,如:新增一条记录,新增完后要显示此记录的结果,由于是两张页面所以保证第一张页面的conn关闭了,第二张页面new出来,就没有问题。
3.这里可以思考这样的连接池,在conn返回到连接池的时候会把conn和session绑定起来,在需要获取一个连接的时候,先要判断所有和session绑定的conn,绑定时间在5秒前的就取消绑定,并把连接放回到freelist列表里,然后是根据传进来sessionID,如果在和session绑定的conn集合中能够找到相同的id那么就再次使用这个conn。如此这般便也可以算是一个连接池。

posted @ 2007-04-07 16:07 狂图 阅读(4087) | 评论 (16)编辑

<2009年7月>
2829301234
567891011
12131415161718
19202122232425
2627282930311
2345678

与我联系

搜索

 

常用链接

留言簿

我的标签

随笔分类

随笔档案

新闻分类

最新评论

  • 1. re: 【原创】数据库连接池问题
  • 这个问题以前遇到过,是Access数据库本身的问题。 当时也很无奈,用了一个很无奈的方法: 在第二个conn执行前加延迟: System.Threading.Thread.Sleep(2000); ...
  • --supersun
  • 2. re: 【原创】数据库连接池问题
  • insert/update/delete之后,commit一下,就是在代码里面显式的写commit 比如 ...(I/U/D操作) command.Text = "commit"...
  • --nani
  • 3. re: 【原创】关于C#多线程安全问题的讨论
  • 代码一: 1private static Object o=new Object(); 2 3public void MyF(){ 4 lock(o){ 5 //dosamethi...
  • --我是菜鸟甲
  • 4. re: 关于C#多线程安全问题的讨论
  • 不理解的是"无论来的是哪个key,都会导致阻赛等待",这个改用"新建一个字典,字典中key就是我们外面的key"后,就没这个问题了吗?
  • --Allen Zhang
  • 5. re: 关于C#多线程安全问题的讨论
  • 呵呵,我来回答你最后的问题。 如果这个集合不是非常巨大并且不需要强行重置正在进行的读取,可以考虑版本控制,这样就不需要锁了,只需更改入口引用即可,旧版本的所有读取完毕后你要怎么处理它都没人抢。 最理想...
  • --A1

阅读排行榜

评论排行榜