最近在研究高並發下,如何准確測得方法執行時間,我想到的辦法是這樣的:可以這樣比喻3000名運動員再跑馬拉松,起點還不同,突然跑道上到了一棵樹,這棵樹又恰好能攔住所有人,待所有人都跑到這顆樹前的時候,樹就挪開了,而此時運動員之間的距離就是最小的。
而我運用lock機制,達到這種效果,只可惜lock似乎對阻塞線程的隊列有一定限制,隊列滿了就一定要放出一個,否則就會報出異常,而且隊列大小似乎是2000~3000線程來着的。
代碼如下:
using System;
using System.Collections.Generic;
using System.Threading;
namespace Test
{
//測試並發時間委托
public delegate void ConcurrencyTest();
/// <summary>
/// 高並發測試類
/// </summary>
public static class HighConcurrencyTest
{
/// <summary>
/// 測試高並發下單個委托的執行時間
/// </summary>
/// <param name="count">並發計數</param>
/// <param name="cTest">委托</param>
/// <param name="sizeThread">一個線程執行的估計時間,可以估計的大些,默認是6毫秒</param>
/// <returns></returns>
public static double StartTest(int count,ConcurrencyTest cTest,int sizeThread=6)
{
#region 為保證之后取得的時間准確度,初始化
ConcurrentLock cLock = new ConcurrentLock();
ConcurrentLock autoLock = new ConcurrentLock();
GC.Collect();
GC.Collect();
GC.Collect();
GC.Collect();
#endregion
#region 測算1億次if時間,並按比例計算出時間差
int max = ((count + 1) * count) / 2;//if被操作的總次數
double stime = new TimeSpan(DateTime.Now.Ticks).TotalMilliseconds;
for (int i = 0; i < 100000000; i++)
{
if (cLock.EndTime == -1)
{
}
}
double etime = new TimeSpan(DateTime.Now.Ticks).TotalMilliseconds;
double ifSpan = ((etime - stime) / 100000000d) * max;
#endregion
#region 清理內存使用,再初始化
GC.Collect();
GC.Collect();
GC.Collect();
GC.Collect();
Thread.Sleep(3000);
#endregion
#region 執行,執行原理如下,因為線程開啟的時間,各個線程之間存在時間差,現在采取一種辦法,使其時間差只是一個if判斷
List<Thread> threads = new List<Thread>();
int current = 0;
for (int i = 0; i < count; i++)
{
var thread = new Thread(() =>
{
//開始,擋路所有線程
lock (autoLock)
{
if (autoLock.StartTime == -1)
{
autoLock.StartTime = new TimeSpan(DateTime.Now.Ticks).TotalMilliseconds;
Thread.Sleep(sizeThread * count);
}
}
//釋放擋路的路牌
#region 委托執行
cTest();
#endregion
//結束使用原子計數器
Interlocked.Increment(ref current);
if (current >= count)
{
//此時所有線程都運行完該委托
autoLock.EndTime = new TimeSpan(DateTime.Now.Ticks).TotalMilliseconds;
}
});
thread.IsBackground = true;
thread.SetApartmentState(ApartmentState.MTA);
threads.Add(thread);
}
foreach (var t in threads)
{
t.Start();
}
foreach (var t in threads)
{
t.Join();
}
#endregion
return (double)(autoLock.EndTime - autoLock.StartTime - sizeThread * count - ifSpan) / (double)count;
}
}
class ConcurrentLock
{
public double StartTime { get; set; }
public double EndTime { get; set; }
public ConcurrentLock()
{
StartTime = -1;
EndTime = -1;
}
public void Reset()
{
StartTime = -1;
EndTime = -1;
}
}
}
