萊蕪金點子廣告電子版2024seo網(wǎng)站推廣價格
場景
有個Service
類,自己在內部實現(xiàn)生產(chǎn)者/消費者
模式。即多個指令輸入該服務后對象后,Service
內部有專門的消費線程執(zhí)行傳入的指令。每個指令的執(zhí)行間隔為1秒
。這里有兩部分組成,
- 工作線程的載體。
new Thread
與Task.Run
。 - 執(zhí)行等待的方法。
Thread.Sleep
與Task.Delay
。
測試環(huán)境
cpu: AMD 3700x 8核16線程
RAM:128G 3200MHz
示例代碼
public class Service
{public Service(int id, Action f, int delayMillisecond = 1000){Id = id;F = f;DelayMillisecond = delayMillisecond;}private int DelayMillisecond;private BlockingCollection<Action> _collection = new BlockingCollection<Action>();public int Id { get; }public Action F { get; }public void AddAction(){_collection.Add(F);}public void Run1(){new Thread(Worker_Sleep).Start();}public void Run2(){new Thread(Worker_Delay).Start();}public void Run3(){Task.Run(Worker_Sleep);}public void Run4(){Task.Run(Worker_Delay);}private void Worker_Sleep(){{foreach (var action in _collection.GetConsumingEnumerable()){action?.Invoke();Thread.Sleep(DelayMillisecond);}}}private async void Worker_Delay(){{foreach (var action in _collection.GetConsumingEnumerable()){action?.Invoke();await Task.Delay(DelayMillisecond);}}}
}
使用BlockingCollection
存儲指令并通過GetConsumingEnumerable
消費。
- run1。
Thread
+Thread.Sleep
。 - run2。
Thread
+Task.Delay
。 - run3。
Task.Run
+Thread.Sleep
。 - run4。
Task.Run
+Task.Delay
。
var serviceCount = 200; // 服務數(shù)量
var actionCount = 3; // 指令個數(shù)
var actionInterval = 1000; // 指令執(zhí)行時間間隔ms
var services = new List<Service>();Action f = () =>
{Console.WriteLine($"{DateTime.Now.ToString("HH:mm:ss ffff")}\t{Thread.CurrentThread.ManagedThreadId}\tCount:{Count}");
};// 生成所有服務對象
for (int i = 0; i < serviceCount; i++)
{var s = new Service(i, f, actionInterval);services.Add(s);
}Console.WriteLine($"{DateTime.Now.ToString("HH:mm:ss ffff")}\tRun");
services.ForEach(s => s.Run2());while (true)
{// 輸入任意內容,啟動var msg = Console.ReadLine();Console.WriteLine($"{DateTime.Now.ToString("HH:mm:ss ffff")}\tStart!!!!!!!!!!");// 每個服務對象自行輸入指令services.ForEach(s =>{for (int i = 0; i < actionCount; i++){s.AddAction();}});
}
測試參數(shù)組為
serviceCount
,50,100,200,500,1000。(其他使用默認)
類型 | 對象個數(shù) | 指令個數(shù) | 間隔 | 完成耗時 |
---|---|---|---|---|
run1 | 50 | 3 | 1 | 2.3s |
run1 | 100 | 3 | 1 | 2.1s |
run1 | 200 | 3 | 1 | 2.2s |
run1 | 500 | 3 | 1 | 2.4s |
run1 | 1000 | 3 | 1 | 2.9s |
run2 | 50 | 3 | 1 | 2.3s |
run2 | 100 | 3 | 1 | 2.5s |
run2 | 200 | 3 | 1 | 3.1s |
run2 | 500 | 3 | 1 | 5.2s |
run2 | 1000 | 3 | 1 | 10.5s |
run3 | 50 | 3 | 1 | 27s |
run3 | 100 | 3 | 1 | 78s |
run3 | 200 | 3 | 1 | - |
run3 | 500 | 3 | 1 | - |
run3 | 1000 | 3 | 1 | - |
run4 | 50 | 3 | 1 | 2.2s |
run4 | 100 | 3 | 1 | 2.1s |
run4 | 200 | 3 | 1 | 2.2s |
run4 | 500 | 3 | 1 | 2.4s |
run4 | 1000 | 3 | 1 | 2.7s |
3個指令,1秒間隔,理想狀態(tài)下,完成耗時應是2秒。且隨著對象個數(shù)增多,仍然能保持在一個合理范圍。
由以上數(shù)據(jù)可知,run1
和run4
是在時間消耗上比較符合期望。
- run1。
Thread
+Thread.Sleep
。 - run4。
Task.Run
+Task.Delay
。
我們更改參數(shù),比較兩者的cpu占用情況。測試參數(shù)如下:
服務數(shù)量:serviceCount=2000
指令個數(shù):actionCount=50
指令執(zhí)行時間間隔/ms:actionInterval = 1000
cpu占用情況如圖。
服務數(shù)量:serviceCount=200
指令個數(shù):actionCount=50
指令執(zhí)行時間間隔/ms:actionInterval = 1000
cpu占用情況如圖。
基于這兩張圖,可以得到初步結論:
Task.Run
+Task.Delay
在初始化階段需要占用較大的cpu資源。后續(xù)較為平穩(wěn),對數(shù)量的增加并不敏感(200到2000)Thread
+Thread.Sleep
在初始化期間與正常運行兩個周期,前后一致性較強。但是對數(shù)量的增加敏感(200到2000)