程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> Parallel Programming-Paralle.For&&ForEach,parallelprogramming

Parallel Programming-Paralle.For&&ForEach,parallelprogramming

編輯:C#入門知識

Parallel Programming-Paralle.For&&ForEach,parallelprogramming


本文主要介紹Parallel.For以及Parallel.ForEach。Parallel.For是普通步長為1的for循環的並行代替方案。Parallel.ForEach是以集合為基准進行循環的foreach的並行代替方案。主要以下內容:

一、Parallel.For

1.1 使用例子

 class ParallelFor
    {
        private void Action(int index)
        {
            Console.WriteLine(index);
            Thread.Sleep(1000);
        }
        public void ParallelAction()
        {
            Parallel.For(0, 10, (i) => Action(i));
        }
    }

 class Program
    {
        static void Main(string[] args)
        {
            var stopwatch = Stopwatch.StartNew();
            stopwatch.Start();
            new ParallelFor().ParallelAction();
            Console.WriteLine(stopwatch.ElapsedMilliseconds);
            Console.Read();
        }
    }

1.2 運行截圖

時間有很大的提升。

二、跳出循環:Break vs Stop

串行執行的for可以使用break/Stop關鍵字直接退出循環。Parallel.For可以通過loopState進行退出或者停止循環。

 class ParallelFor
    {
        private void Action(int index)
        {
            Console.WriteLine(index);
            Thread.Sleep(1000);
        }
        public void ParallelAction()
        {
            Parallel.For(0, 10, (i, loopState) =>
            {
                if (i == 8)
                {
                    loopState.Break();//loopState.Stop()
                }
                Action(i);
            });
        }
    }

LoopState是循環體的第一個參數(可選),第一個是i。

三、 Break和Stop的區別

當Break執行時,小於當前的index(i)的操作都會保證執行完成,大於當前index的迭代不再開始(不是不再執行)-》已經開始的還是會繼續執行。

Break indicates that no iterations after the current iteration should be run. It effectively cancels any additional iterations of the loop. However, it does not stop any iterations that have already begun execution. 

進一步說明:當index為8的循環開始執行時,index為1,2,3的循環不一定已經開始了。所以當Break執行後(index為8),會保證沒有執行的1,2,3執行完畢

比如上面的例子i==8時,進行break,上面的代碼執行截圖:

0-7保證執行,8也打印出來了(有可能還會有10,9),是因為index8對應的循環在break之前已經開始了。

當Stop執行時,Parallel會用最快的速度結束循環,如果小於當前執行stop的index對應的循環操作還沒有開始,則不會執行這些沒有開始的。所以Stop比Break能夠更加快速的結束迭代。

Calling the Stop method indicates that any iterations of the loop that have not yet started need not be run. It effectively cancels any additional iterations of the loop. However, it does not stop any iterations that have already begun execution.

Calling the Stop method causes the IsStopped property to return true for any iteration of the loop that is still executing. This is particularly useful for long-running iterations, which can check the IsStopped property and exit early if its value is true.

Stop is typically employed in search-based algorithms, where once a result is found, no other iterations need be executed.

Break和Stop不能同時使用,會有異常拋出。

四、Continue功能。

Parallel.For是沒有Continue關鍵字的,簡單的使用Return即可完成Continue的功能。

 public void ParallelAction()
{
            Parallel.For(0, 10, (i) =>
            {
                if (i == 10)
                {
                    return;
                }
                Action(i);
            });
}

五、ParallelOptions

Parallel.For通用有ParallelOptions這個屬性,通過這個可以指定CancellationSourceToken和MaxDegreeOfParallelism(最大並發數)

 public void ParallelAction()
 {
            var cts = new CancellationTokenSource();
            var option = new ParallelOptions()
            {
                CancellationToken = cts.Token,
                MaxDegreeOfParallelism = 5
            };
            Parallel.For(0, 10, option, (i) =>
            {
                if (cts.Token.IsCancellationRequested)
                {
                    return;
                }
                Action(i);
            });
 }

 六、Partitioner

本文一直在講解Parallel.For上面的操作對於Parallel.ForEach都是通用的。但是Parallel.ForEach有個特殊功能。Partitioner。

6.1 例子

class ParallelForEach
{
        public void ParallelAction()
        {
            int[] items = new int[100000];
            Parallel.ForEach(Partitioner.Create(0, 100000, 50000), (range) =>
            {
                Console.WriteLine("IN Parallel");
                for (var i = range.Item1; i < range.Item2; i++)
                {
                    items[i] = i;
                }
            });
        }
}

上面代碼的把1000000次分成兩個50000進行,這兩個50000之間是並行執行的,但是在每個50000(range)是串行自己執行的。上面程序會打印出兩"IN Parallel"。

6.2說明

為什麼要使用Partitioner?使用並行開發有兩大開銷,一是線程調度,二是調度代理方法,如果循環體本身開銷很小,大量使用線程會得不償失:調度本身的開銷大於使用並行帶來的性能提升。上面的例子可以看出,使用Partitioner減少了並行的次數,增大了循環體的體積。達到了並行和調度開銷的協調。

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