多线程并发测试类库
WEB项目中除了单元测试,还经常需要多线程测试一个方法是否存在并发问题,或者是否有性能问题。每次都要写测试代码总是一件很累的事情。于是写了这一个多线程测试的类库,用来进行快速的多线程并发测试。
多线程并发测试时,需要等所有线程测试结束后通知主线程,主线程才能进行下一步动作,这里主要用到了ManualResetEvent。ManualResetEvent 类表示一个本地等待处理事件,在已发事件信号后必须手动重置该事件。通常,此通信涉及一个线程在其他线程进行之前必须完成的任务。当一个线程开始一个活动(此活动必须完成后,其他线程才能开始)时,它调用 Reset 以将 ManualResetEvent 置于非终止状态。此线程可被视为控制 ManualResetEvent。调用 ManualResetEvent 上的 WaitOne 的线程将阻止,并等待信号。当控制线程完成活动时,它调用 Set 以发出等待线程可以继续进行的信号。并释放所有等待线程。一旦它被终止,ManualResetEvent 将保持终止状态,直到它被手动重置。即对 WaitOne 的调用将立即返回。可以通过将布尔值传递给构造函数来控制 ManualResetEvent 的初始状态,如果初始状态处于终止状态,为 true;否则为 false。
多线程并发测试由以下步骤完成:
- 创建并发测试的线程数,先创建的线程等待最后一个线程创建完成。
 - 所有线程执行待测试的方法,返回测试的结果。
 - 等所有线程执行完成后,进入思考时间等待。
 - 继续进行循环测试。
 
我们来看这个多线程并发测试的代码。
| 
 1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
27 
28 
29 
30 
31 
32 
33 
34 
35 
36 
37 
38 
39 
40 
41 
42 
43 
44 
45 
46 
47 
48 
49 
50 
51 
52 
53 
54 
55 
56 
57 
58 
59 
60 
61 
62 
63 
64 
65 
66 
67 
68 
69 
70 
71 
72 
73 
74 
75 
76 
77 
78 
79 
80 
81 
82 
83 
84 
85 
86 
87 
88 
89 
90 
91 
92 
93 
94 
95 
96 
97 
98 
99 
100 
101 
102 
103 
104 
105 
106 
107 
108 
109 
110 
111 
112 
113 
114 
115 
116 
117 
118 
119 
120 
121 
122 
123 
124 
125 
126 
127 
128 
129 
130 
131 
132 
133 
134 
135 
136 
137 
138 
139 
140 
141 
142 
143 
144 
145 
146 
147 
148 
149 
150 
151 
152 
153 
154 
155 
156 
157 
158 
159 
160 
161 
162 
163 
164 
165 
166 
167 
168 
169 
170 
171 
172 
173 
174 
175 
176 
177 
178 
179 
180 
181 
182 
183 
184 
185 
186 
187 
188 
189 
190 
191 
192 
193 
194 
195 
196 
197 
198 
199 
200 
201 
202 
203 
204 
205 
206 
207 
208 
209 
210 
211 
212 
213 
214 
215 
216 
217 
218 
219 
220 
221 
222 
223 
224 
225 
226 
227 
228 
229 
230 
231 
232 
233 
234 
235 
236 
237 
238 
239 
240 
241 
242 
243 
244 
245 
246 
247 
248 
249 
250 
251 
252 
253 
254 
255 
256 
257 
258 
259 
260 
261 
262 
263  | 
using System; using System.Collections.Generic; using System.Diagnostics; using System.Threading; /// <summary> /// 并发测试 /// </summary> public class ConcurrentTest : IDisposable {     #region 私有方法     /// <summary>     /// 测试方法所在的接口     /// </summary>     private Func<bool> func;     /// <summary>     /// 主线程控制信号     /// </summary>     private ManualResetEvent manualResetEvent;     /// <summary>     /// 测试线程控制信号     /// </summary>     private ManualResetEvent threadResetEvent;     /// <summary>     /// 待执行的线程数     /// </summary>     private List<int> threads;     /// <summary>     /// 测试结果     /// </summary>     private List<ConcurrentTestResult> results;     /// <summary>     /// 执行测试的成功数     /// </summary>     private int successCount;     /// <summary>     /// 执行测试的失败数     /// </summary>     private int failureCount;     /// <summary>     /// 测试耗时     /// </summary>     private long elapsedMilliseconds;     /// <summary>     /// 当前线程     /// </summary>     private int currentIndex;     /// <summary>     /// 当前测试的总线程数     /// </summary>     private int currentCount;     /// <summary>     /// 思考时间     /// </summary>     private int thinkTime;     /// <summary>     /// 重复次数     /// </summary>     private int repeatCount;     /// <summary>     /// 测试计时器     /// </summary>     private Stopwatch stopwatch;     #endregion     #region 构造函数     /// <summary>     /// 构造函数     /// </summary>     public ConcurrentTest()     {         manualResetEvent = new ManualResetEvent(true);         threadResetEvent = new ManualResetEvent(true);         stopwatch = new Stopwatch();     }     #endregion     #region 执行测试     /// <summary>     /// 执行多线程测试     /// </summary>     /// <param name="threadCount">需要测试的线程数</param>     /// <param name="func">待执行方法</param>     /// <returns></returns>     public List<ConcurrentTestResult> Execute(int threadCount, Func<bool> func)     {         return Execute(threadCount, 1, func);     }     /// <summary>     /// 执行多线程测试     /// </summary>     /// <param name="threadCount">需要测试的线程数</param>     /// <param name="repeatCount">重复次数</param>     /// <param name="func">待执行方法</param>     /// <returns></returns>     public List<ConcurrentTestResult> Execute(int threadCount, int repeatCount, Func<bool> func)     {         return Execute(threadCount, 0, repeatCount, func);     }     /// <summary>     /// 执行多线程测试     /// </summary>     /// <param name="threadCount">需要测试的线程数</param>     /// <param name="thinkTime">思考时间,单位耗秒</param>     /// <param name="repeatCount">重复次数</param>     /// <param name="func">待执行方法</param>     /// <returns></returns>     public List<ConcurrentTestResult> Execute(int threadCount, int thinkTime, int repeatCount, Func<bool> func)     {         return Execute(new List<int>() { threadCount }, thinkTime, repeatCount, func);     }     /// <summary>     /// 执行多线程测试     /// </summary>     /// <param name="threads">分别需要测试的线程数</param>     /// <param name="thinkTime">思考时间,单位耗秒</param>     /// <param name="repeatCount">重复次数</param>     /// <param name="func">待执行方法</param>     /// <returns></returns>     public List<ConcurrentTestResult> Execute(List<int> threads, int thinkTime, int repeatCount, Func<bool> func)     {         this.func = func;         this.threads = threads;         this.thinkTime = thinkTime;         this.repeatCount = repeatCount;         CheckParameters();         CreateMultiThread();         return this.results;     }     #endregion     #region 验证参数     /// <summary>     /// 验证参数     /// </summary>     private void CheckParameters()     {         if (func == null) throw new ArgumentNullException("func不能为空");         if (threads == null || threads.Count == 0) throw new ArgumentNullException("threads不能为空或者长度不能为0");         if (thinkTime < 0) throw new Exception("thinkTime不能小于0");         if (repeatCount <= 0) throw new Exception("repeatCount不能小于等于0");     }     #endregion     #region 创建多线程并执行测试     /// <summary>     /// 创建多线程进行测试     /// </summary>     private void CreateMultiThread()     {         results = new List<ConcurrentTestResult>(threads.Count);         foreach (int threadCount in threads)         {             for (int repeat = 0; repeat < repeatCount; repeat++)             {                 //主线程进入阻止状态                 manualResetEvent.Reset();                 //测试线程进入阻止状态                 threadResetEvent.Reset();                 stopwatch.Reset();                 currentCount = threadCount;                 currentIndex = 0;                 successCount = 0;                 failureCount = 0;                 elapsedMilliseconds = 0;                 for (int i = 0; i < currentCount; i++)                 {                     Thread t = new Thread(new ThreadStart(DoWork));                     t.Start();                 }                 //阻止主线程,等待测试线程完成测试                 manualResetEvent.WaitOne();                 results.Add(new ConcurrentTestResult()                 {                     FailureCount = failureCount,                     SuccessCount = successCount,                     ElapsedMilliseconds = elapsedMilliseconds                 });                 Thread.Sleep(thinkTime);             }         }     }     /// <summary>     /// 执行测试方法     /// </summary>     private void DoWork()     {         bool executeResult;         Interlocked.Increment(ref currentIndex);         if (currentIndex < currentCount)         {             //等待所有线程创建完毕后同时执行测试             threadResetEvent.WaitOne();         }         else        {             //最后一个线程创建完成,通知所有线程,开始执行测试             threadResetEvent.Set();             //开始计时             stopwatch.Start();         }         //执行测试         executeResult = func();         Interlocked.Decrement(ref currentIndex);         if (currentIndex == 0)         {             //最后一个线程执行的测试结束,结束计时             stopwatch.Stop();             elapsedMilliseconds = stopwatch.ElapsedMilliseconds;             //保存测试结果             if (executeResult)                 Interlocked.Increment(ref successCount);             else                Interlocked.Increment(ref failureCount);             //通知主线程继续             manualResetEvent.Set();         }         else        {             //保存测试结果             if (executeResult)                 Interlocked.Increment(ref successCount);             else                Interlocked.Increment(ref failureCount);         }     }     #endregion     #region 释放资源     /// <summary>     /// 释放资源     /// </summary>     public void Dispose()     {         manualResetEvent.Close();         threadResetEvent.Close();     }     #endregion } /// <summary> /// 并发测试结果 /// </summary> public class ConcurrentTestResult {     /// <summary>     /// 当前执行线程总数     /// </summary>     public int ThreadCount     {         get { return SuccessCount + FailureCount; }     }     /// <summary>     /// 测试成功数     /// </summary>     public int SuccessCount { get; set; }     /// <summary>     /// 测试失败数     /// </summary>     public int FailureCount { get; set; }     /// <summary>     /// 总耗时     /// </summary>     public long ElapsedMilliseconds { get; set; } } | 
使用起来就非常简单了,我们看测试代码:
| 
 1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
27 
28 
29 
30 
31  | 
class Program {     static void Main(string[] args)     {         using (ConcurrentTest concurrentTest = new ConcurrentTest())         {             var result = concurrentTest.Execute(5, -1, 10, new TestClass().Execute);             foreach (var item in result)             {                 Console.WriteLine("线程数:{0}\t成功:{1}\t失败:{2}\t耗时:{3}",                     item.ThreadCount, item.SuccessCount, item.FailureCount, item.ElapsedMilliseconds);             }         }         Console.ReadKey(true);     } } public class TestClass {     public bool Execute()     {         int tempValue = GetRandom();         System.Threading.Thread.Sleep(tempValue);         return tempValue % 2 == 0;     }     private int GetRandom()     {         return new Random().Next(990, 1000);     } } | 
测试类库提供了4个Execute方法的重载,一般情况下能满足我们的多线程并发测试场景了。
另一地址:http://blog.moozi.net/archives/multi-threaded-concurrent-test-library.html