程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> 線程系列02,多個線程同時處理一個耗時較長的任務以節省時間,02節省時間

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

編輯:C#入門知識

線程系列02,多個線程同時處理一個耗時較長的任務以節省時間,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);
            }
        }
    }

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

 

□ 同時使用多個線程

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

 

 

線程系列包括:

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

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

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


多個線程調用同一個線程函數

你提到的線程函數是一般函數還是生成線程的函數,或是用於運行特定函數的線程?

如果是在用VC中想用多個線程運行同樣的任務,而這些任務之間沒有通訊問題和內存共享的問題,那可以用下面的模板:
DWORD WINAPI TaskThreadProc(LPVOID)
{
// 獨立任務
// ...
}

void RunTaskUseMultiThread(int nThreadCount) // 線程個數為nThreadCount
{
HANDLE* threads = new HANDLE[nThreadCount]; // 線程句柄,對線程進行狀態的控制時用到
DWORD* idThreads = new DWORD[nThreadCount]; // 線程id,給線程發消息時用到
int i;
for (i = 0; i < nThreadCount; i++)
{
threads[i] = CreateThread( NULL, 0, TaskThreadProc, NULL, CREATE_SUSPENDED, &idThreads[i]); // 創建線程
}
for (i = 0; i < nThreadCount; i++) // 由於生成的是CREATE_SUSPENDED的線程,所以這裡開始讓線程開始運行
ResumeThread(threads[i]);
WaitForMultipleObjects(nThreadCount, threads, TRUE, INFINITE); // 等待線程運行結束
for (i = 0; i < nThreadCount; i++)
CloseHandle(threads[j]); // 銷毀線程
delete [] threads;
delete [] idThreads;
}
 

一個很耗時間的循環分成兩個循環放入不同的線程,使線程同步可以不可以提高效率

首先明確一點,單核CPU,多線程運算,其實是每個線程申請一段時間,只不過時間太短,好像是同時執行,耗時運算,一般會加入等待界面並新啟一個線程運算,運算完回調,效率問題一個硬件解決,一個優化算法
 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved