天天看點

多核時代 .NET Framework 4 中的并行程式設計7---任務工廠和任務計劃

1. 任務工廠TaskFactory

提供對建立和計劃 Task 對象的支援.其中TaskFactory提供了以下幾種構造函數:

Ø TaskFactory() 使用預設配置初始化 TaskFactory 執行個體。

Ø TaskFactory(CancellationToken) 使用指定配置初始化 TaskFactory 執行個體,使用此構造函數,我們就可以在需要的時候取消相應的并行計算.

Ø  TaskFactory(TaskScheduler) 使用指定配置初始化 TaskFactory 執行個體。 

Ø TaskFactory(TaskCreationOptions, TaskContinuationOptions) 使用指定配置初始化 TaskFactory 執行個體。

其中TaskCreationOptions枚舉可選擇以下幾種之一:

(1)     None 指定應使用預設行為。 

(2)     PreferFairness 提示 TaskScheduler 以一種盡可能公平的方式安排任務,這意味着較早安排的任務将更可能較早運作,而較晚安排運作的任務将更可能較晚運作。 

(3)     LongRunning 指定某個任務将是運作時間長、粗粒度的操作。它會向TaskScheduler 提示,過度訂閱可能是合理的。 

(4)     AttachedToParent 指定将任務附加到任務層次結構中的某個父級。 

TaskContinuationOptions是為通過使用 ContinueWith 或 ContinueWith 方法建立的連續任務指定行為,可以選擇以下枚舉幾種之一:

(1)     None 預設情況下,完成前面的任務之後将安排運作延續任務,而不考慮前面任務的最終 TaskStatus。 

(2)      PreferFairness 提示 TaskScheduler 以一種盡可能公平的方式安排任務,這意味着較早安排的任務将更可能較早運作,而較晚安排運作的任務将更可能較晚運作。 

(3)      LongRunning 指定某個任務将是運作時間長、粗粒度的操作。 它會向TaskScheduler 提示,過度訂閱可能是合理的。 

(4)      AttachedToParent 指定将任務附加到任務層次結構中的某個父級。 

(5)      NotOnRanToCompletion 指定不應在延續任務前面的任務已完成運作的情況下安排延續任務。 

(6)      NotOnFaulted 指定不應在延續任務前面的任務引發了未處理異常的情況下安排延續任務。 NotOnCanceled 指定不應在延續任務前面的任務已取消的情況下安排延續任務。

(7)      OnlyOnRanToCompletion 指定隻應在延續任務前面的任務已完成運作的情況下才安排延續任務。

(8)      OnlyOnFaulted 指定隻應在延續任務前面的任務引發了未處理異常的情況下才安排延續任務。 

(9)      OnlyOnCanceled 指定隻應在延續任務前面的任務已取消的情況下才安排延續任務。

(10)    ExecuteSynchronously 指定應同步執行延續任務。指定此選項後,延續任務将在導緻前面的任務轉換為其最終狀态的相同線程上運作。 如果在建立延續任務時已經完成前面的任務,則延續任務将在建立此延續任務的線程上運作。隻應同步執行運作時間非常短的延續任務。

Ø TaskFactory(CancellationToken, TaskCreationOptions, TaskContinuationOptions, TaskScheduler) 使用指定配置初始化TaskFactory 執行個體。

TaskFactory建立任務示例代碼如下:

1)   直接建立并啟動任務:

var task = Task.Factory.StartNew(() =>

            {

                Console.WriteLine("DateTime is {0}", DateTime.Now);

            });

2)   建立并啟動可以取消的任務:

var canceltoken = new CancellationTokenSource();

            var token = canceltoken.Token;

            var task = Task.Factory.StartNew(() =>

                for (int i = 0; i < 1000; i++)

                {

                    if (token.IsCancellationRequested)

                    {

                        Console.WriteLine("CancellationRequested!");

                        throw new OperationCanceledException(token);

                    }

                    else

                        Console.WriteLine("i={0}", i);

                        Thread.Sleep(1 * 1000);

                }

            }, token);

       canceltoken.Cancel();

2. TaskScheduler

表示一個處理将任務排隊到線程中的低級工作的對象. TaskScheduler是個抽象類,我們可以根據需要通過繼承TaskScheduler類,來實作自己的任務計劃.

3. 延續任務.

在異步程式設計中,一個異步操作在完成時調用另一個操作并将資料傳遞到其中的情況非常常見。 傳統上,此過程是通過使用回調方法完成的。 在任務并行庫中,“延續任務”提供了同樣的功能。 延續任務(也簡稱為“延續”)是一個異步任務,由另一個任務(稱為“前面的任務”)在完成時調用。

盡管延續相對容易使用,但也十分強大和靈活。 例如,您可以:

Ø 将資料從前面的任務傳遞到延續

Ø 指定将調用或不調用延續所依據的精确條件

Ø 在延續啟動之前取消延續,或在延續正在運作時以協作方式取消延續

Ø 提供有關應如何安排延續的提示

Ø 從同一前面的任務中調用多個延續

Ø 在多個前面的任務中的全部或任意任務完成時調用一個延續

Ø 将延續依次相連,形成任意長度

Ø 使用延續來處理前面的任務所引發的異常

1)   通過使用 Task.ContinueWith 方法建立延續. 例如:

Task firstGen = new Task(() =>

                Console.WriteLine("Message from first generation task");

                throw new Exception();

            Task secondGen1 = firstGen.ContinueWith(antecedent =>

                Console.WriteLine("Antecedent task faulted with type:{0}", antecedent.Exception.GetType());

            }, TaskContinuationOptions.OnlyOnFaulted);

            Task secondGen2 = firstGen.ContinueWith(antecedent =>

                Console.WriteLine("Antecedent task NOT faulted");

            }, TaskContinuationOptions.NotOnFaulted);

            firstGen.Start();

            Console.WriteLine("Press enter to finish");

            Console.ReadLine();

上面的代碼通過ContinueWith方法建立延續任務.在建立完延續任務後,我們調用第1個任務的Start()方法來開始任務的執行(如上面代碼的firstGen.Start();).

2)   ContinueWith<T>建立帶傳回值的延續任務。關于傳回值,需要說明的是:

Ø 當父任務和延續的子任務都沒有傳回值時,則可使用Task.Factory.ContinueWhenAll()和Task.Factory.ContinueWhenAny()建立延續任務。

Ø 當父任務沒有傳回值,而延續的子任務都有傳回值時,則可Task<T>.Factory.ContinueWhenAll()和Task<T>.Factory.ContinueWhenAny()建立延續任務。

Ø 當父任務有傳回值,而延續的子任務沒有傳回值時,則可Task.Factory.ContinueWhenAll<T>()和Task.Factory.ContinueWhenAny<T>()建立延續任務。

Ø 當父任務和延續的子任務都有傳回值時,則可Task<T>.Factory.ContinueWhenAll<V>()和Task<T>.Factory.ContinueWhenAny<V>()建立延續任務。

代碼如下:

class BankAccount

    {

        public int Balance

        {

            get;

            set;

        }

    }

Task<BankAccount> rootTask = new Task<BankAccount>(() =>

                BankAccount account = new BankAccount();

                    account.Balance++;

                return account;

            Task<int> continuationTask1 = rootTask.ContinueWith<int>((Task<BankAccount> antecedent) =>

            {

                Console.WriteLine("Interim Balance 1:{0}", antecedent.Result.Balance);

                return antecedent.Result.Balance * 2;

            Task continuationTask2 = continuationTask1.ContinueWith((Task<int> antecedent) =>

                Console.WriteLine("Final balance 1:{0}", antecedent.Result);

            rootTask.ContinueWith<int>((Task<BankAccount> antecedent) =>

                Console.WriteLine("Interim Balance 2:{0}", antecedent.Result.Balance);

                return antecedent.Result.Balance / 2;

            }).ContinueWith((Task<int> antecedent) =>

                Console.WriteLine("Final Balance 2:{0}", antecedent.Result);

            rootTask.Start();

3)   ContinueWhenAll建立延續任務,等待一組任務中全部都完成時執行延續任務。ContinueWhenAny建立延續任務,等待一組任務中任何一個任務完成時執行延續任務。代碼如下:

BankAccount account = new BankAccount();

            Task<int>[] tasks = new Task<int>[10];

            for (int i = 0; i < 10; i++)

                tasks[i] = new Task<int>((stateObjectt) =>

                    int isolatedBalance = (int)stateObjectt;

                    for (int j = 0; j < 1000; j++)

                        isolatedBalance++;

                    return isolatedBalance;

                }, account.Balance);

            }

            Task continuation = Task.Factory.ContinueWhenAll<int>(tasks, antecedents =>

                foreach (Task<int> t in antecedents)

                    account.Balance += t.Result;

            foreach (Task t in tasks)

                t.Start();

            try

                continuation.Wait();

            catch (AggregateException agex)

                agex.Flatten().Handle(inner =>

                    Console.WriteLine("Handled Exception of type:{0}", inner);

                    return true;

                });

           Console.WriteLine("Expected value {0}, Balance: {1}", 10000, account.Balance);

4. TaskFactory和TaskScheduler

TaskFactory和TaskScheduler的關系是:任務工廠負責任務Task的建立,而任務計劃則負責相關任務有條不紊的執行排程.

    本文轉自風車車  部落格園部落格,原文連結:http://www.cnblogs.com/xray2005/archive/2011/09/03/2165866.html,如需轉載請自行聯系原作者

繼續閱讀