1. 程式人生 > >Parallel類

Parallel類

urn src 遍歷 tde foreach 返回值 靜態 all eve

Parallel類

Parallel類是對線程的一個抽象。該類位於System.Threading.Tasks名稱空間中,提供了數據和任務並行性。
  Paraller類定義了數據並行地For和ForEach的靜態方法,以及任務並行的Invoke的靜態方法。Parallel.For()和Parallel.ForEach()方法在每次叠代中調用相同的代碼,Paraller.Invoke()允許調用不同的方法。

1.Parallel.For
  Parallel.For()方法類似C#語法的for循環語句,多次執行一個任務。但該方法並行運行叠代,叠代的順序沒有定義。
  Parallel.For()方法中,前兩個參數定義了循環的開頭和結束,第三個參數是一個Action委托。Parallel.For方法返回類型是ParallelLoopResult結構,它提供了循環是否結束的信息。
  Parallel.For有多個重載版本和多個泛型重載版本。
  示例:

技術分享
     static void ForTest()
        {
            ParallelLoopResult plr =
                Parallel.For(0,10,i => {
                    Console.WriteLine("{0},task:{1},thread:{2}",i,Task.CurrentId,Thread.CurrentThread.ManagedThreadId);
                    Thread.Sleep(5000);
                });

            if (plr.IsCompleted)
                Console.WriteLine("completed!");

        }
技術分享

  輸出:
  技術分享

  任務不一定映射到一個線程上。線程也可以被不同的任務重用。


  上面的例子,使用了.NET 4.5中新增的Thread.Sleep方法,而不是Task.Delay方法。Task.Delay是一個異步(http://www.cnblogs.com/afei-24/p/6757361.html)方法,用於釋放線程供其它任務使用。
  示例:

技術分享
  static void ForTestDelay()
        {
            ParallelLoopResult plr =
                Parallel.For(0, 10,async i => {
                    Console.WriteLine("{0},task:{1},thread:{2}", i, Task.CurrentId, Thread.CurrentThread.ManagedThreadId);
                    await Task.Delay(1000);
                    Console.WriteLine("{0},task:{1},thread:{2}", i, Task.CurrentId, Thread.CurrentThread.ManagedThreadId);
                });

            if (plr.IsCompleted)
                Console.WriteLine("completed!");

            Console.ReadKey();

        }
技術分享

  輸出:
  技術分享
  上面代碼使用了await關鍵字進行延遲,輸出結果顯示延遲前後的代碼運行在不同的線程中。而且延遲後的任務不再存在,只留下線程,這裏還重用了前面的線程。另一個重要的方面是,Parallel類的For方法並沒有等待延遲,而是直接完成。parallel類只等待它創建的任務,而不等待其它後臺活動。所以上面代碼使用了Console.ReadKey();使主線程一直運行,不然很可能看不到後面的輸出。

2.提前停止Parallel.For
  For()方法的一個重載版本接受第三個Action<int,ParallelLoopState>委托類型的參數。使用這個方法可以調用ParallelLoopState的Break()或Stop()方法,以停止循環。
  註意,前面說到,叠代的順序是沒有定義的。
  示例:

技術分享
static void ForStop()
        {
            ParallelLoopResult plr =
                Parallel.For(0,10,(int i,ParallelLoopState pls)=> {
                    Console.WriteLine("{0},task:{1},thread:{2}", i, Task.CurrentId, Thread.CurrentThread.ManagedThreadId);
                    if (i > 5)
                        pls.Break();
                });

            Console.WriteLine("is completed:{0}",plr.IsCompleted);
            Console.WriteLine("最低停止索引:{0}",plr.LowestBreakIteration);
        }
技術分享

  輸出:
  技術分享
  叠代值在大於5時中斷,但其它已開始的任務同時執行。


3.對Parallel.For中的每個線程初始化
  Parallel.For方法使用多個線程來執行循環,如果需要對每個線程進行初始化,就可以使用Parallel.For<TLocal>()方法。除了from和to對應的值之外,Parallel.For方法的泛型版本還接受3個委托參數:
    第一個委托參數的類型是Func<TLocal>,這個方法僅對用於執行叠代的每個線程調用每一次。
    第二個委托參數為循環體定義了委托。該參數類型是Func<int, ParallelLoopState, TLocal, TLocal>。其中第一個參數是循環叠代,第二個參數ParallelLoopState允許停止循環,第三個參數接受從上面參數委托  Func<TLocal>返回的值,該委托還需返回一個TLocal類型的值。該方法對每次叠代調用。
    第三個委托參數指定一個委托Action<TLocal>,接受第二個委托參數的返回值。這個方法僅對用於執行叠代的每個線程調用每一次。

  示例:

技術分享
      static void ForInit()
            {
                ParallelLoopResult plr =
                    Parallel.For(0,10,()=> {
                        Console.WriteLine("init thread:{0},task:{1}",Thread.CurrentThread.ManagedThreadId,Task.CurrentId);
                        return Thread.CurrentThread.ManagedThreadId.ToString();
                    },
                    (i, pls,strInit)=> {
                        Console.WriteLine("body:{0},strInit:{1},thraed:{2},task:{3}",i,strInit,Thread.CurrentThread.ManagedThreadId,Task.CurrentId);
                        return i.ToString();
                    },
                    (strI)=> {
                        Console.WriteLine("finally {0}",strI);
                    });
            }
技術分享

  輸出:
  技術分享


4.Parallel.ForEach
  Parallel.ForEach方法遍歷實現了IEnumerable的集合,類似於foreach,但以異步方式遍歷。沒有確定遍歷順序。

  示例:

1 2 3 4 5 6 7 8 9 10 11 static void ForeachTest() { string[] data = { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve" }; ParallelLoopResult plr = Parallel.ForEach<string>(data, s => { Console.WriteLine(s); }); if (plr.IsCompleted) Console.WriteLine("completed!"); }

  如果需要中斷,可以使用ForEach的重載版本和參數ParallelLoopState。
  訪問索引器:

    ParallelLoopResult plr1 = Parallel.ForEach<string>(data, (s,pls,l) =>
            {
                Console.WriteLine("data:{0},index:{1}",s,l);
            });

5.Parallel.Invoke
  如果多個任務並行運行,可以使用Parallel.Invoke方法。該方法允許傳遞一個Action委托數組。

技術分享
    static void ParallerInvoke()
        {
            Action[] funs = { Fun1,Fun2};

            Parallel.Invoke(funs);
        }

        static void Fun1()
        {
            Console.WriteLine("f1");
            Console.WriteLine("task:{0},thread:{1}", Task.CurrentId, Thread.CurrentThread.ManagedThreadId);
        }
        static void Fun2()
        {
            Console.WriteLine("f2");
            Console.WriteLine("task:{0},thread:{1}", Task.CurrentId, Thread.CurrentThread.ManagedThreadId);
        }
技術分享

Parallel類