線程系列02,多個線程同時處理一個耗時較長的任務以節省時間


當面對一個耗時較長的任務時,我們可以把這個任務切分成多個部分,然后同時交給多個線程處理。

 

□ 統計字節數組一個比較耗時的方式

以下來統計一個字節數組的大小。

    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);
            }
        }
    }

3

如果把統計工作同時交給多個線程,是否可以把統計時間省下來呢?

 

□ 同時使用多個線程

現在要對"統計字節數組大小"這個任務進行均分、切分。首先面臨的問題是:按什么標准均分?
--這個完全是靠個人喜好,可以讓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,用來保證執行完上一個線程再執行下一個線程

5
在這里,使用多線程同時處理一個任務,效率差不多提高了2.6倍!

 

總結:
○ 對於一個比較耗時的任務可以同時交給多個線程處理
○ 線程的實例方法Join保證執行完上一個線程再執行下一個線程

 

 

線程系列包括:

線程系列01,前台線程,后台線程,線程同步

線程系列02,多個線程同時處理一個耗時較長的任務以節省時間

線程系列03,多線程共享數據,多線程不共享數據

線程系列04,傳遞數據給線程,線程命名,線程異常處理,線程池

線程系列05,手動結束線程

線程系列06,通過CLR代碼查看線程池及其線程

線程系列07,使用lock語句塊或Interlocked類型方法保證自增變量的數據同步

線程系列08,實現線程鎖的各種方式,使用lock,Montor,Mutex,Semaphore以及線程死鎖

線程系列09,線程的等待、通知,以及手動控制線程數量

線程系列10,無需顯式調用線程的情形


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM