正文

Hashtable 的多线程自同步测试2008-03-03 22:14:00

【评论】 【打印】 【字体: 】 本文链接:http://blog.pfan.cn/tujun/33157.html

分享到:

以前多线程使用Hashtable的时候,都是使用lock(Hashtable)的方式进行同步,那天在网上忽然查到一个资料,就是Hashtable 对于多线程是安全的,可以实现自同步,也就是不需要lock也能实现同步,于是写了段代码测试:private Hashtable mObjectHash = null;//定义一个哈希表 private int mMaxCount = 50000;//定义最大对象数///定义的测试对象类private class mShowObject{public int ID=-1;public String Name;public override string ToString(){ return String.Format("{0}\t{1}", this.ID, this.Name); } } ///定义的一些变量,用于计数 long threadAccess = 0; int deleteObjectcount = 0;int addobjectCount = 0;int editobjectcount = 0;DateTime startTime = DateTime.Now;//启动时间bool mActive = false;int mChangeThreadCount = 0;Random rnd = null;//构造函数public Form1(){ InitializeComponent();mObjectHash = Hashtable.Synchronized(new Hashtable(mMaxCount));//初始化一个具有自同步属性的哈希表rnd = new Random((int)DateTime.Now.Ticks);}private void AddObject(mShowObject obj){ if (obj == null) return;lock (mObjectHash){%%%%    if (mObjectHash.ContainsKey(obj.ID)) return;//此处因为判断和添加事务之间可能会出现不同的结果,因此,需要手动同步 mObjectHash.Add(obj.ID, obj);}}private void EditObject(mShowObject obj){if (obj == null) return;if (mObjectHash.ContainsKey(obj.ID)) { mObjectHash[obj.ID] = obj; }else mObjectHash.Add(obj.ID, obj);}private void RemoveObject(int id){if (mObjectHash.ContainsKey(id))mObjectHash.Remove(id); }private mShowObject GetObject(int key){if (mObjectHash.ContainsKey(key))return (mShowObject)mObjectHash[key];return null; }//一个访问哈希表的线程private void ChangeThread(){startTime = DateTime.Now;//启动时间while (mActive){Interlocked.Increment(ref threadAccess);Thread.Sleep(0);Random rnd1 = new Random();int key = rnd1.Next(this.mMaxCount);int Command = rnd1.Next(Int32.MaxValue);if ((Command % 3) == 1){mShowObject obj = GetObject(key);if (obj != null){obj.Name = String.Format("对象{0},修改于{1} #$", rnd.Next(mMaxCount), DateTime.Now.ToString("HH:mm:ss")); EditObject(obj);Interlocked.Increment(ref editobjectcount); } } else if ((Command % 3) == 2){RemoveObject(key);Interlocked.Increment(ref deleteObjectcount); } else if ((Command % 3) == 0){ mShowObject obj = new mShowObject();obj.ID = this.mObjectHash.Count;obj.Name = String.Format("对象{0},创建于{1}", rnd.Next(mMaxCount), DateTime.Now.ToString("HH:mm:ss")); AddObject(obj);Interlocked.Increment(ref addobjectCount); } } }//初始化对象private void button1_Click(object sender, EventArgs e) { for (int i = 0; i < mMaxCount; i++){ mShowObject obj = new mShowObject();obj.ID = i;obj.Name = String.Format("对象{0},创建于{1}", rnd.Next(mMaxCount), DateTime.Now.ToString("HH:mm:ss")); AddObject(obj); } mActive = true; }//启动线程private void button2_Click(object sender, EventArgs e){for (int i = 0; i < 400; i++)//启动400个线程{Thread t = new Thread(new ThreadStart(this.ChangeThread)); t.IsBackground = true;t.Start();Interlocked.Increment(ref mChangeThreadCount); } }//使用定时器显示线程执行状态private void timer1_Tick(object sender, EventArgs e){TimeSpan ts = DateTime.Now - startTime;float speed = threadAccess / (float)ts.TotalSeconds; this.label1.Text = String.Format("修改线程数量:{0:n0},哈希表对象数量:{1:n0},线程执行次数:{2:n0},删除对象数:{3:n0},修改对象数:{4:n0},增加对象数:{5:n0},速度:{6:n0}/s", mChangeThreadCount, this.mObjectHash.Count, threadAccess, deleteObjectcount, editobjectcount, addobjectCount, speed); }下面是运行截图:我的电脑是AMD闪龙2500+,512M内存,开400个线程的情况下大概每秒执行4万次访问,没有出现错误;而加了"%%%% "的那一行如果没有手工进行同步,就会出现问题,但是修改函数删除函数中没有进行手工同步却没有影响,估计是往哈希表添加项的时候需要做更多的事情,造成线程阻塞,多线程访问时候就出现了添加重复键的问题,而删除和编辑因为哈希表的索引很快,线程几乎没有阻塞,所以没有出错吧! 使用自同步在这里的确能提高一些性能,但是并不明显,因为对哈希表的操作都要执行2个步骤:先确定是否有指定的键,然后再决定是否添加删除或者修改,但凡要执行2步以上才能完成的操作,仅仅依靠对象自身的同步是绝对不安全的,因此,这里只讨论多线程下的安全操作,而不是讨论性能,性能的优化应该是尽可能的压缩同步范围,在同步期间少做与哈希表对象无关的操作,并且避免死锁. .Net下,实现自同步的对象还有ArrayList,Queue等,经测试,最能体现性能的就是Queue,因为它只有一种操作:编辑(压入/弹出),因此在避开过多无谓的同步代码后,性能提高十分明显.

阅读(5887) | 评论(0)


版权声明:编程爱好者网站为此博客服务提供商,如本文牵涉到版权问题,编程爱好者网站不承担相关责任,如有版权问题请直接与本文作者联系解决。谢谢!

评论

暂无评论
您需要登录后才能评论,请 登录 或者 注册