2016年11月22日 星期二

[C#] .Net Framework 3.5 在For迴圈中跑執行緒

Net Framework 4 推出了Parallel.For ,讓迴圈中發揮多核心的威力,簡化許多。

但在.Net Framework 3.5 中並沒有這種好東西可以用,如果要實作在F or迴圈中擠出

多核心的效能,可以用以下方式實作。


首先介紹ManualResetEvent ,這是一個很好用的東西,可以用來卡住目前的流程。

ManualResetEvent.Reset時,流程會卡住在ManualResetEvent.WaitOne()的地方,直到

ManualResetEvent.set()為止,若一直忘記Reset,會卡到無怨無悔,畫面臉色發白。

以下是一個簡單的範例,當所有執行緒執行完畢後,才會印出目前時間。




using System;
using System.Threading;
using System.Diagnostics;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApplication
{
    public class Program
    {
        public static void Main(string[] args)
        {
            new Program();
        }
        
        //Define Thread Control Var
        int DoneCount = 0;
        int DoneRequired =0;
        ManualResetEvent mre = new ManualResetEvent(false);
        
        public Program()
        {
         round();
        }
        
        private void round()
        {
               int N=10;
               ParameterizedThreadStart pts ;
               Thread mThread;
               
               DoneCount = 0;
               DoneRequired =N;
            
               mre.Reset();
              for (int i=0;i<N;i++)
              {
                pts = new ParameterizedThreadStart(ThreadFunction);
                mThread=new Thread(pts);
                mThread.Start(i);
              }
             //wait all thread finish 
             mre.WaitOne();
             Console.Write("Done "+DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss")+Environment.NewLine);
        }
        
         private void ThreadFunction(object data)
        {             
            int n=Convert.ToInt32(data);
            
            System.Threading.Thread.Sleep(n*100);
                 
            Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss")+" sleep:"+n*100);
            Interlocked.Increment(ref DoneCount);           
            if (DoneCount == DoneRequired)
            {
                mre.Set();
            }
        }
      
    }
}

執行結果:


2016-11-22 10:22:34 sleep:0
2016-11-22 10:22:34 sleep:100
2016-11-22 10:22:34 sleep:200
2016-11-22 10:22:34 sleep:300
2016-11-22 10:22:34 sleep:400
2016-11-22 10:22:35 sleep:500
2016-11-22 10:22:35 sleep:600
2016-11-22 10:22:35 sleep:700
2016-11-22 10:22:35 sleep:800
2016-11-22 10:22:35 sleep:900
Done 2016-11-22 10:22:35

如果我們沒有使用ManualResetEvent來控制流程,則會變成以下結果

把mre.set()以及mre.WaitOne()註解掉


Done 2016-11-22 10:25:15
2016-11-22 10:25:15 sleep:0
2016-11-22 10:25:15 sleep:100
2016-11-22 10:25:15 sleep:200
2016-11-22 10:25:15 sleep:300
2016-11-22 10:25:15 sleep:400
2016-11-22 10:25:15 sleep:500
2016-11-22 10:25:15 sleep:600
2016-11-22 10:25:15 sleep:700
2016-11-22 10:25:15 sleep:800
2016-11-22 10:25:16 sleep:900

就會變成我也不知道Thread何時跑完,但我己先印出結束時間了。

沒有留言:

張貼留言