當面對一個耗時較長的任務時,我們可以把這個任務切分成多個部分,然后同時交給多個線程處理。
□ 統計字節數組一個比較耗時的方式
以下來統計一個字節數組的大小。
class Program
{static byte[] values = new byte[500000000];static void Main(string[] args){GenerateByteArray();Console.WriteLine("正在統計字節數");
Stopwatch watch = new Stopwatch();
watch.Start();long total = 0;
for (int i = 0; i < values.Length; i++){total += values[i];}watch.Stop();Console.WriteLine("統計結果為:" + total);
Console.WriteLine("計算時間為:" + watch.Elapsed);
}static void GenerateByteArray(){var r = new Random(987);
for (int i = 0; i < values.Length; i++){values[i] = (byte)r.Next(10);
}}}
如果把統計工作同時交給多個線程,是否可以把統計時間省下來呢?
□ 同時使用多個線程
現在要對"統計字節數組大小"這個任務進行均分、切分。首先面臨的問題是:按什么標准均分?
--這個完全是靠個人喜好,可以讓2個線程,3個線程......來處理。在這里,就根據CPU的數量來均分,因為CPU的數量可以通過Environment.ProcessorCount獲得。
面臨的第二問題是:均分什么?
--比如有4個CPU
--那可以把任務分成4個線程同時處理
--把字節數組的長度均分,比如字節數組的長度是1000,均分成4段,每段長度為250
--把字節數組的大小分成4個放一個數組里,即[sum1, sum2, sum3, sum4],所有的元素加起來就是字節數組的總大小
class Program
{static byte[] values = new byte[500000000];//分段統計的大小放該數組,比如分成4等份,[10000,10005,10008,10009]
private static long[] partialSum;//把values數組長度均等分,比如長度1000,分成4粉,那partialSize就是250
private static int partialSize;static void Main(string[] args){//根據CPU的數量確定數組的長度
partialSum = new long[Environment.ProcessorCount];//根據CPU的數量確定數組長度均等分
partialSize = values.Length/Environment.ProcessorCount;GenerateByteArray();Console.WriteLine("正在統計字節數");
Stopwatch watch = new Stopwatch();
watch.Start();long total = 0;
for (int i = 0; i < values.Length; i++){total += values[i];}watch.Stop();Console.WriteLine("統計結果為:" + total);
Console.WriteLine("計算時間為:" + watch.Elapsed);
Console.WriteLine();watch.Reset();watch.Start();Thread[] threads = new Thread[Environment.ProcessorCount];
for (int i = 0; i < Environment.ProcessorCount; i++){threads[i] = new Thread(SumPartial);
threads[i].Start(i);}//保證一個線程結束再執行下一個線程
for (int i = 0; i < Environment.ProcessorCount; i++){threads[i].Join();}//統計總大小
long total2 = 0;
for (int i = 0; i < Environment.ProcessorCount; i++){total2 += partialSum[i];}watch.Stop();Console.WriteLine("使用分段線程統計的大小:" + total2);
Console.WriteLine("計算時間為:" + watch.Elapsed);
}/// <summary>
/// 分段統計字節數組的大小
/// </summary>
/// <param name="partialNumber">比如有4個CPU,partialNumber可能的值是0, 1, 2, 3</param>
static void SumPartial(object partialNumber){long sum = 0;
int partialNumberAsInt = (int)partialNumber;int baseIndex = partialNumberAsInt * partialSize;
for (int i = baseIndex; i < baseIndex + partialSize; i++){sum += values[i];}partialSum[partialNumberAsInt] = sum;}/// <summary>
/// 創建字節數組
/// </summary>
static void GenerateByteArray(){var r = new Random(987);
for (int i = 0; i < values.Length; i++){values[i] = (byte)r.Next(10);
}}}
以上,統計字節數組大小的方式倒不是最重要的,線程部分才是重點:
○ 有幾個CPU,就有幾個線程
○ 線程的實例方法Start可以傳遞object類型的參數
○ 線程的實例方法Join,用來保證執行完上一個線程再執行下一個線程
在這里,使用多線程同時處理一個任務,效率差不多提高了2.6倍!
總結:
○ 對於一個比較耗時的任務可以同時交給多個線程處理
○ 線程的實例方法Join保證執行完上一個線程再執行下一個線程
線程系列包括: