對於 Thread 和 ThreadPool 已經是元老級別的類了。Thread 是 C# 語言對執行緒物件的封裝,它從 .NET 1.0 版本就有了,然後 ThreadPool 是 .Net Framework 2.0 版本中出現的,都是相當成熟的存在。
當然,現在已經出現了 Task 和 PLinq 等更高效率的並行類,執行緒和執行緒池在實際開發中逐漸減少了,但是不能不知道他們的用法,因為總有需要對接的內容,別人用了你也得能看懂。
本文將結合範例,簡單介紹下 Thread 和 ThreadPool。
Thread 類的功能就是,建立和控制執行緒,設定其優先順序並獲取其狀態。
下邊程式碼簡單範例說明下 Thread 的相關內容:
public static void Main()
{
// (1)
//var th1 = new Thread(ExecuteInForeground);
//th1.Start();
// (2)
//var th2 = new Thread(ExecuteInForeground);
//th2.IsBackground = true;
//th2.Start();
// (3)
//ThreadPool.QueueUserWorkItem(ExecuteInForeground);
Thread.Sleep(1000);
// Console.WriteLine($"主執行緒 ({Thread.CurrentThread.ManagedThreadId}) 即將退出 執行 Join() 方法。。。");
// th2.Join();
Console.WriteLine($"主執行緒 ({Thread.CurrentThread.ManagedThreadId}) 即將退出。。。");
//Console.ReadLine();
}
private static void ExecuteInForeground(object state)
{
var sw = Stopwatch.StartNew();
Console.WriteLine("執行緒 {0}: {1}, 優先順序: {2}",
Thread.CurrentThread.ManagedThreadId,
Thread.CurrentThread.ThreadState,
Thread.CurrentThread.Priority);
do
{
Console.WriteLine("執行緒 {0}: 計時 {1:N2} 秒",
Thread.CurrentThread.ManagedThreadId,
sw.ElapsedMilliseconds / 1000.0);
Thread.Sleep(500);
} while (sw.ElapsedMilliseconds <= 5000);
sw.Stop();
}
註釋部分三組執行緒啟動的結果如下三圖:
第 1 部分,是前臺執行緒,必須執行完畢,主執行緒才會退出,所以一直執行到 5s 之前。
第 2、3 部分,均為後臺執行緒,當主執行緒執行完成之時,無論是否執行完成直接中斷,所以只回圈了兩次就退出了。
關於 Join() 方法
程式碼中th2.Join()
如果在後臺執行緒上執行,這結果如下圖,將會等待後臺執行緒完成後主執行緒才結束。
由於執行緒物件的建立時需要分配記憶體,GC 過程中銷燬物件,然後整合零散的記憶體塊,從而佔用 CPU 資源,會影響程式效能,所以 ThreadPool 誕生了。
注意,託管執行緒池中的執行緒是後臺執行緒,其 IsBackground 屬性為 true。
下面是一個關於執行緒池的幾個屬性值,以及開啟新的後臺執行緒並傳入引數的範例:
//存放要計算的數值的欄位
public static double num1 = -1;
public static double num2 = -1;
static void Main(string[] args)
{
int workerThreads, completionPortThreads;
// public static void GetMaxThreads (out int workerThreads, out int completionPortThreads);
ThreadPool.GetMaxThreads(out workerThreads, out completionPortThreads);
Console.WriteLine($"執行緒池中輔助執行緒的最大數目:{workerThreads}");
Console.WriteLine($"執行緒池中非同步 I/O 執行緒的最大數目:{completionPortThreads}");
Console.WriteLine();
// public static void GetMinThreads(out int workerThreads, out int completionPortThreads);
ThreadPool.GetMinThreads(out workerThreads, out completionPortThreads);
Console.WriteLine($"執行緒池根據需要建立的最少數量的輔助執行緒:{workerThreads}");
Console.WriteLine($"執行緒池根據需要建立的最少數量的非同步 I/O 執行緒:{completionPortThreads}");
Console.WriteLine();
ThreadPool.SetMaxThreads(100, 15); // set 的值必須是 Min~Max 之間的值,否則會設定不成功
ThreadPool.GetMaxThreads(out workerThreads, out completionPortThreads);
Console.WriteLine($"set 執行緒池中輔助執行緒的最大數目:{workerThreads}");
Console.WriteLine($"set 執行緒池中非同步 I/O 執行緒的最大數目:{completionPortThreads}");
Console.WriteLine();
// 命名引數 傳入後臺執行緒
int num = 2;
// 啟動第一個任務:計算x的8次方
Console.WriteLine("啟動第一個任務:計算{0}的8次方.", num);
ThreadPool.QueueUserWorkItem(new WaitCallback(TaskProc1), num);
// 啟動第二個任務
Console.WriteLine("啟動第二個任務:計算{0}的8次方", num);
ThreadPool.QueueUserWorkItem(new WaitCallback(TaskProc2), num);
// 等待兩個數值等完成計算
while (num1 == -1 || num2 == -1) ;
//列印計算結果
Console.WriteLine($"{num} 的 8 次方為 {num1} {num2}");
Console.ReadLine();
}
private static void TaskProc2(object state)
{
Console.WriteLine($"TaskProc2-Thread-{Thread.CurrentThread.IsBackground}");
num1 = Math.Pow(Convert.ToDouble(state), 8);
}
private static void TaskProc1(object state)
{
num2 = Math.Pow(Convert.ToDouble(state), 8);
}
輸出結果:
如下程式碼,在沒有單擊確認鍵之前,程式會一直列印遞增數位,當收到回車指令後,cts.Cancel();
被執行,後臺執行緒就取消成功了。
static void Main(string[] args)
{
CancellationTokenSource cts = new CancellationTokenSource();
ThreadPool.QueueUserWorkItem(t => Counts(cts.Token, 1000));
Console.WriteLine("Press Any Key to cancel the operation");
Console.ReadLine();
cts.Cancel();
Console.ReadLine();
}
private static void Counts(CancellationToken token, int CountTo)
{
for (int count = 0; count < CountTo; count++)
{
if (token.IsCancellationRequested)
{
Console.WriteLine("Count is cancelled");
break;
}
Console.WriteLine(count);
Thread.Sleep(200);
}
Console.WriteLine("Count is stopped");
}
結果如下圖:
如下程式碼,分別執行 100 次,看最終需要的時間成本:
public static void Main()
{
Stopwatch sw = new Stopwatch();
sw.Start();
for (int i = 0; i < 100; i++)
{
Thread th = new Thread(() =>
{
int count = 0;
count++;
});
th.Start();
}
sw.Stop();
Console.WriteLine("執行建立執行緒所需要的時間為:" + sw.ElapsedMilliseconds);
sw.Restart();
for (int i = 0; i < 100; i++)
{
ThreadPool.QueueUserWorkItem(t =>
{
int count = 0;
count++;
});
}
sw.Stop();
Console.WriteLine("執行執行緒池所需要花費的時間:" + sw.ElapsedMilliseconds);
Console.ReadLine();
}
如下圖,明顯執行緒池效能更佳:
參考:https://learn.microsoft.com/zh-cn/dotnet/api/system.threading.threadpool?view=net-7.0
https://learn.microsoft.com/zh-cn/dotnet/api/system.threading.thread?view=net-7.0
本文來自部落格園,作者:橙子家,微訊號:zfy1070491745,有任何疑問歡迎溝通,一起成長。
轉載本文請註明原文連結:https://www.cnblogs.com/czzj/p/ThreadPool.html