往往我们在开发程序、调试程序时,无法模拟多用户同时操作的实际环境下的运行情况。
为了模拟多用户并发操作,我们先写个多线程的例子来充分模拟多用户并发的情况
Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/--> class SequenceTest
{
/// <summary>
/// 定义委托
/// </summary>
/// <param name="user">用户</param>
delegate void MakeSequenceDelegate(string user);
/// <summary>
/// 这里是测试序列
/// </summary>
/// <param name="user">用户</param>
private void MakeSequence(string user)
{
for (int i = 0; i < 10; i++)
{
BaseSequenceManager sequenceManager = new BaseSequenceManager();
// 模拟2010年7月份的订单编号产生
System.Console.WriteLine(user + ":" + sequenceManager.GetSequence("Order201007"));
}
}
/// <summary>
/// 这里是模拟多用户同时点击
/// </summary>
public void DoTest()
{
// 模拟3个用户的并发操作
MakeSequenceDelegate sequenceDelegate1 = new MakeSequenceDelegate(MakeSequence);
sequenceDelegate1.BeginInvoke("user1", null, null);
MakeSequenceDelegate sequenceDelegate2 = new MakeSequenceDelegate(MakeSequence);
sequenceDelegate2.BeginInvoke("user2", null, null);
MakeSequenceDelegate sequenceDelegate3 = new MakeSequenceDelegate(MakeSequence);
sequenceDelegate3.BeginInvoke("user3", null, null);
}
}
序列表的设计效果如下图,表中存储了当前是什么序列的序号为多少等信息。
由于没进行并发控制,程序的输出情况如下,当然在单用户操作测试时,是不太可能测试出并发情况下的运行状态的。
这里会有重复序列急丢失序列的情况会发生,并不能保证多用户并发时,能完全产生唯一的订单编号。
为什么会发生并发问题? 因为你在读的时候,我也在读,你在更新序列时,我也在更新序列,因为相同的程序在运行多份,用户1,2同时都读到了0007这个序号。
进行并发控制后的运行效果如下:
这里序号是连续的,而且是没有丢失情况,也没重复情况发生。
这里是如何避免并发?BaseSequenceManager中进行了如下排斥并发的加工。
private static readonly object SequenceLock = new object();
string returnValue = string.Empty;
// 这里用锁的机制,提高并发控制能力 lock (SequenceLock) {
returnValue = 读取数据库中的当前序列值(一)
更新数据库中的序列(二)
}
return returnValue;
因为数据库的读取,更新,需要2步操作,是导致了并发问题的所在。
以上文章主要涉及到如下技术问题:
1:需要能写出多线程的模拟程序。
2:多线程函数如何传递参数需要学会。
3:这也算是所谓的核心基础组件的自动化测试吧。
4: lock 语句(C# 参考) http://msdn.microsoft.com/zh-cn/library/c5kehkcz(VS.80).aspx
测试起来好用的管理软件,真正投放到实际生产环境中往往会发生很多意想不到的错误,这往往是没能重复测试多用户并发情况下的运行情况导致的占一部分。
以上程序虽然没什么大难度,下午耗费了接近2-3个小时,才调整好,希望对读者评估工作量能有个参考。
估计在国内的管理类软件,90%以上都没进行严格的多用户并发测试,90%以上的都没考虑应用程序并发问题及数据库的并发问题,若不是迫不得已越简单越省事就好,何必跟自己过不去呢,搞那么多繁琐的并发处理。 |