(譯)Asynchronous programming and Threading in C# (.NET 4.5)


原文地址:http://www.codeproject.com/Articles/996857/Asynchronous-programming-and-Threading-in-Csharp-N

介紹:

Asynchronous programming and threading is very important feature for concurrent or parallel programming. Asynchronous programming may or may not use threading. Still if we can see them together, I think we may have better understanding of both the features.

在並發、並行編程中,異步編程和線程是非常重要的功能。異步編程可能用到了線程,也可能沒有。如果能一起了解他們,我認為我們能更好的了解兩者的特點。

Topics covered in this article

  1. Asynchronous programming
  2. Is threading required
  3. Task based Asynchronous Programming
  4. Parallel programming:
  5. Conclusion

文章目錄:

  1. 異步編程
  2. 線程是否是必須的
  3. 基於Task的異步編程
  4. 並行編程
  5. 結論

Asynchronous Programming

異步編程

Asynchronous operation means that the operation runs independent of main or other process flow. In general c# program starts executing from the Main method and ends when the Main method returns. In between all the operations runs sequentially one after another. One operation must wait until its previous operation finishes. Let’s see following code:

異步操作意思是:操作獨立於主進程或其他進程。一般的C#程序在主方法執行時開始,在主方法返回時結束。在此期間,所有的操作會一個接一個的順序執行。一個操作必須等待前一個操作完成。讓我們看看下面的代碼:

1     static void Main(string[] args)
2         {
3            DoTaskOne();
4            DoTaskTwo();
5         }

Method “DoTaskTwo” would not be started until “DoTaskOne” finishes. In other words method “DoTaskOne” blocks the execution as long it takes to finish.

方法DoTaskTwo必須等到DoTaskOne完成才會開始執行。換句話說就是方法DoTaskOne在運行期間阻塞了DoTaskTwo運行。

In asynchronous programming a method is called that runs in the background and the calling thread is not blocked. After calling the method the execution flow immediately backs to calling thread and performs other tasks. Normally it uses Thread or Task (We will discuss Thread and Task in detail later).

在異步編程中,方法調用是在后台運行的,不會阻塞調用的線程;並且在調用方法后立即返回調用線程執行其他任務。通常,我們使用Thread或Task進行異步編程(稍后我們會詳細的討論Thread和Task)。

In our case if we run the “DoTaskOne” asynchronously, after calling the “DoTaskOne” method, execution flow immediately backs to Main method and start “DoTaskTwo”.

在我們的例子中,如果我們異步運行DoTaskOne,在調用DoTaskOne方法后,會立即返回主線程開始執行DoTaskOneTwo。

We can create our own thread using Thread class or use asynchronous patterns provided by .NET to perform asynchronous programming. There are three different asynchronous patterns in .NET:

我們可以通過Thread類或.Net為實現異步編程提供的異步模式創建我們自己的線程。.Net提供了三種不同的編程模式:

1.Asynchronous Programming Model (APM) pattern  異步編程模型(APM)模式

2.Event-based Asynchronous Pattern (EAP)  基於時間的異步編程模式(EAP)

Both the above models are not recommended by Microsoft so we will not discuss about them. If you are interested you can read more from following msdn link:

上面兩種模型微軟不推薦使用,所以我們不會討論他們,如果你有興趣,可以從下面的MSDN鏈接了解更多:

https://msdn.microsoft.com/en-us/library/ms228963(v=vs.110).aspx

https://msdn.microsoft.com/en-us/library/ms228969(v=vs.110).aspx

3.Task-based Asynchronous Pattern (TAP):基於Task的異步模式 ,此模型推薦使用,因此我們會詳細討論。

Threading is required or not

線程是不是必須的

If we use asynchronous programming pattern that .NET introduced in 4.5, in most of the cases we need not to create manual thread by us. The compiler does the difficult work that the developer used to do.

如果使用.NET 4.5介紹的異步編程模式,大部分情況下我們不需要手動創建線程。編譯器做了開發者需要做的困難工作。。

Creating a new tread is costly, it takes time. Unless we need to control a thread, then “Task-based Asynchronous Pattern (TAP)” and “Task Parallel Library (TPL)” is good enough for asynchronous and parallel programming. TAP and TPL uses Task (we will discuss what is Task latter). In general Task uses the thread from ThreadPool(A thread pool is a collection of threads already created and maintained by .NET framework. If we use Task, most of the cases we need not to use thread pool directly. Still if you want to know more about thread pool visit the link:https://msdn.microsoft.com/en-us/library/h4732ks0.aspx)

創建一個新的線程是昂貴的,它需要一定的時間。對於異步和並行編程,基於任務的編程模式(TAP)和任務並行庫(TPL)已經足夠好了,除非我們需要控制一個線程。TAP和TPL使用Task(稍后我們討論什么是Task)。一般情況下,Task通過線程池使用線程。(線程池是由.NET framework創建並維護的線程集合。如果使用Task,大多數情況下我們不需要直接用線程池。如果你想了解更多關於線程池的內容,請訪問https://msdn.microsoft.com/en-us/library/h4732ks0.aspx)。

 

But Task can be run:

  1. In the current thread
  2. In a new thread
  3. In a thread from the thread pool
  4. Or even without any thread

線程可以運行在:

  1. 當前線程
  2. 一個新的線程
  3. 線程池中的線程
  4. 甚至不使用線程

But if we use Task, as a developer we need not to worry about creation or uses of the thread, .NET framework handles the inner difficulties for us.

作為開發者,如果我們使用Task,我們不需要擔心線程的創建和使用,.NET framework為我們處理了內部的難點。

Anyway if we need some control over the thread like,

  1. We want to set a name for the tread
  2. We want to set priority for the thread
  3. We want to make our thread foreground or background

Then we may have to create our own thread using thread class.

如果我們需要控制線程,必須:

  1. 設置線程的名字
  2. 設置線程的優先級
  3. 設置前台或后台線程

那可以用Thread類創建我們自己的線程。

Creating Thread using Thread class

用Thread類創建線程

The constructor of Thread class accepts a delegate parameter of type

  1. ThreadStart: This delegate defines a method with a void return type and no parameter.
  2. And ParameterizedThreadStart: This delegate defines a method with a void return type and one object type parameter.

Thread類的構造函數接受委托參數類型:

  1. ThreadStart:這個委托定義了一個沒有參數、沒返回值的方法。
  2. 還是ParameterizedThreadStart:這個委托定義了一個沒返回值、有一個object類型參數的方法。

Following is the simple example how we can start a new thread with Start method:

下面是一個簡單的例子,告訴我們怎樣通過Start方法開啟一個新的線程:

1         static void Main(string[] args)
2         {
3             Thread thread = new Thread(DoTask);
4             thread.Start();// Start DoTask method in a new thread
5             //Do other tasks in main thread
6         }
7         static public void DoTask() {
8             //do something in a new thread       
9         }    

We can use lamda expression instead of named method:

我們可以用lamda表達式代替方法:

1         static void Main(string[] args)
2         {
3             Thread thread = new Thread(() => {
4                 //do something in a new thread
5             });
6             
7             thread.Start();// Start a new thread
8             //Do other tasks in main thread
9         }

If we don’t require the variable reference we can even start the thread directly like:

如果不需要變量引用,我們甚至可以像這樣開啟線程:

1         static void Main(string[] args)
2         {
3             new Thread(() => {
4                 //do something in a new thread
5             }).Start();// Start a new thread
6 
7             //Do other tasks in main thread
8         }

But if we want to control the tread object after it is created we require the variable reference. We can assign different values to the different properties of the object like:

 但是如果想控制創建后的線程對象,我們需要變量引用。可以給對象的不同屬性設置不同的值,比如:

 1         static void Main(string[] args)
 2         {
 3             Thread thread = new Thread(DoTask);
 4            
 5             thread.Name = "My new thread";// Asigning name to the thread
 6             thread.IsBackground = false;// Made the thread forground
 7             thread.Priority = ThreadPriority.AboveNormal;// Setting thread priority
 8             thread.Start();// Start DoTask method in a new thread
 9             //Do other task in main thread
10         }

With the reference variable we can perform some function like abort the thread or wait for the thread to complete by calling the join method. If we call join to a thread the main thread blocks until the calling thread completes.

利用引用的變量,我們可以執行一些功能,如終止線程、等待線程執行完成。。。。(這里不知道怎么翻譯好,略過)

If we want to pass some data to the method we can pass it as a parameter of Start method. As the method parameter is object type we need to cast it properly.

如果想向方法傳遞一些數據,我們可以通過Start方法的參數傳遞。這個方法的參數是object類型,我們需要正確的傳遞。

 1         static void Main(string[] args)
 2         {
 3          Thread thread = new Thread(DoTaskWithParm);
 4          thread.Start("Passing string");// Start DoTaskWithParm method in a new thread
 5          //Do other task in main thread
 6         }
 7         static public void DoTaskWithParm(object data)
 8         {
 9 
10             //we need to cast the data to appropriate object
11 
12         }

“async” and “await” keywords (async和await關鍵字)

.NET framework introduced two new keywords to perform asynchronous programing: “async” and “await”. To use “await” keyword within a method we need to declare the method with “async” modifier. “await” keyword is used before calling an asynchronous method. “await” keyword suspends further execution of the method and control is return to the calling thread. See the example:

.NET framework 為進行異步編程介紹了兩個關鍵字:async和await。要在方法中使用await關鍵字,我們需要定義用async修飾的方法。await關鍵字被使用在調用異步方法的前面,它延緩了方法的進一步執行,並且控制器返回到調用的線程。看下例子:

1 private async static void CallerWithAsync()// 使用async修飾
2 {
3 string result = await GetSomethingAsync();// await 用在方法調用前面. It suspends //execution of CallerWithAsync() method and control returs to the calling thread that can //perform other task.
4 
5 Console.WriteLine(result);// 這行代碼在GetSomethingAsync()完成前不會執行 //method completes
6 }

The “async” modifier can only be used with methods returning a Task or void. It cannot be used with the entry point of a program, the Main method.

async關鍵字只能修飾返回Task或void的方法,它不能用在程序的入口,主方法上。

We cannot use await keyword before all the methods. To use “await” the method must have to return “awaitable” type. Following are the types that are “awaitable”:

  1. Task
  2. Task<T>
  3. Custom “awaitable” type. Using a custom type is a rare and advanced scenario; we will not discuss it here.

並不是所有的方法都能使用await關鍵字,必須是返回“可等待”類型的方法。下面的類型是可等待的:

  1. Task
  2. Task<T>
  3. 自定義“可等待”類型,這比較少見,我們這里不討論。

Task-based Asynchronous Pattern(基於任務的異步模式)

First of all we need an asynchronous method that returns Task or Task<T>. We can create Task by following ways:

  1. Task.Factory.StartNew method: Prior to .NET 4.5 (in .NET 4) this was the primary method to create and schedule a task.
  2. Task.Run or Task.Run<T> Method: From .NET 4.5 this method should be used. This method is sufficient for most of the common cases.
  3. Task.FromResult method: If the result is already computed, we can use this method to create a task.

首先我們需要一個返回Task或Task<T>的異步方法,可以通過下面的方式創建:

  1. Task.Factory.StartNew 方法:.NET4.5之前(在.NET 4),是創建和調度任務的主要方法。
  2. Task.Run 或 Task.Run<T>方法:從.NET 4.5開始使用,大多數情況下,這個方法已經足夠了。
  3. Task.FromResult方法:如果結果已經計算好了,我們可以用這個方法創建任務。

Task.Factory.StartNew has still some important uses for advance scenario. Please see the link for more information: 

Task.Factory.StartNew 在在一些先進案例中有很多重要的作用。更多信息請查看鏈接:http://blogs.msdn.com/b/pfxteam/archive/2011/10/24/10229468.aspx

Following links shows some ways to create Task:

更多創建Task的方式: http://dotnetcodr.com/2014/01/01/5-ways-to-start-a-task-in-net-c/

Creating and awaiting for a Task (創建和等待任務)

We will create our Task using Task.Run<T> method. This method Queues the specified work to run on the ThreadPool and returns a task handle for that work. Following steps are needed to create an asynchronous Task from a synchronous method:

我們將會使用Task.Run<T>方法創建Task。這個方法會給指定的工作排隊,工作是運行在線程池上,並返回一個Task。下面是從一個異步方法創建異步任務的步驟:

  1. Let’s assume that we have a method that is synchronous but take some time to complete:

假設我們有一個同步方法,執行完成需要一定時間:

1        static string Greeting(string name)
2         {
3         Thread.Sleep(3000);
4 
5         return string.Format("Hello, {0}", name);
6 
7        }
  1. To access this method asynchronously we have to wrap it with an asynchronous method. Let’s assume the name is “GreetingAsync”. It is a convention to add “Async” suffix to the name of an asynchronous method.

異步的訪問這個方法,我們需要用異步的方法包裝它。假設名稱是GreetingAsync。通常會在異步方法后面加Async 后綴。

1                       static Task<string> GreetingAsync(string name)
2                          {
3                                return Task.Run<string>(() =>
4                                      {
5                                         return Greeting(name);
6                                       });
7                      }
  1. Now we can call the asynchronous method GreetingAsync by using the await keyword

現在我們可以用await關鍵字調用異步方法GreetingAsync了:

1                     private async static void CallWithAsync()
2                         {
3                              //some other tasks
4                                 string result = await GreetingAsync("Bulbul");
5                                 //We can add  multiple &ldquo;await&rdquo; in same &ldquo;async&rdquo; method
6                                //string result1 = await GreetingAsync(&ldquo;Ahmed&rdquo;);
7                               //string result2 = await GreetingAsync(&ldquo;Every Body&rdquo;);
8                               Console.WriteLine(result);
9                      }

When “CallWithAsync” method is called it starts executing like regular synchronous method until it reaches “await” keyword. When it reaches to the “await” keywords it poses execution for the method and start waiting for “GreetingAsync("Bulbul")” method to be finished. In the meantime the control returns to the caller of “CallWithAsync” method and the caller can do its other task as usual.

當“CallWithAsync”方法被調用時,它會像常規同步方法一樣開始執行,直到到達await關鍵字。await關鍵字會使當前方法等待GreetingAsync("bulbul")方法完成。在此期間控制器會返回到CallWithAsync調用線程並去做其他任務。

When “GreetingAsync("Bulbul")” method finishes, “CallWithAsync” method resumes its other task after “await” keywords. In this case it executes the code “Console.WriteLine(result)

當GreetingAsync("Bulbul")方法完成后,CallWithAsync方法 恢復await關鍵字后面的其他任務的執行。這個例子中,是執行代碼“Console.WriteLine(result)”。

  1. Continuation with Task: “ContinueWith” method of Task class defines the code that should be invoked as soon as the task is completed.

任務的延續:Task的ContinueWith方法定義了必須在task完成之后執行的代碼

 1                            private static void CallWithContinuationTask()
 2                                  {
 3                                     Task<string> t1 = GreetingAsync("Bulbul");
 4                                    t1.ContinueWith(t =>
 5 
 6                                         {
 7 
 8                                              string result = t.Result;
 9 
10                                              Console.WriteLine(result);
11                                        });
12                                }

We need not to use “await” keyword if we use “ContinueWith” method, compiler will put the “await” keyword into appropriate place.

當我們用ContinueWith方法時,不需要await關鍵字,編譯器會在適當的地方生成。

Awaiting for multiple asynchronous methods(等待多個異步方法)

Let us look at the following code:

1                    private async static void CallWithAsync()
2                         {
3                              string result = await GreetingAsync("Bulbul");
4                              string result1 = await GreetingAsync(&ldquo;Ahmed&rdquo;);
5                              Console.WriteLine(result);
6                             Console.WriteLine(result1);
7                    }

Here we are awaiting for the two calling sequentially. Second call of the “GreetingAsync(“Ahmed”)” will be started after finishing the first call “GreetingAsync("Bulbul")”. If “result” and “result1” of the above code are not dependent, then the sequential “awiting” is not a good practice.

In that case we can simply call the methods without “await” keywords and “awaits” for them in a single place by combinators. In that case both the method call can be executed in parallel.

這里等待了兩個順序調用。第二個調用會在第一個調用王成后開始。如果上面代碼中的“result”和“result1”不相互歷來,那么順序等待(awaiting)不是一個好的方式。

在這種情況下,我們可以不用”await“關鍵字簡單的調用,已組合的方式在一個地方等待他們。這時兩個方法調用是並行執行的。

 

 1                       private async static void MultipleAsyncMethodsWithCombinators()
 2                         {
 3 
 4                            Task<string> t1 = GreetingAsync("Bulbul");
 5 
 6                            Task<string> t2 = GreetingAsync("Ahmed");
 7 
 8                            await Task.WhenAll(t1, t2);
 9 
10                          Console.WriteLine("Finished both methods.\n " +
11 
12                         "Result 1: {0}\n Result 2: {1}", t1.Result, t2.Result);
13                       }

Here we use Task.WhenAll combinator. Task.WhenAll creates a task that will complete when all of the supplied tasks have completed. Task class has another combinator. Task.WhenAny, that will complete when any of the supplied tasks have completed.

這里我們用Task.WhenAll 方法,它會在所有任務完成時返回一個任務。Task類還有另一個組合方法,Task.WhenAny,它會在給定任務任意一個完成時結束。

Handling Exceptions(異常處理)

We have to put “await” code blocks inside a try block to handle the exception of the method.

我們必須在try代碼塊中用await代碼來處理方法的異常

 1                    private async static void CallWithAsync()
 2                       {
 3                           try
 4                           {
 5                               string result = await GreetingAsync("Bulbul");
 6                           }
 7                         catch (Exception ex)
 8                          {
 9                         Console.WriteLine(&ldquo;handled {0}&rdquo;, ex.Message);
10                         }
11              }

If we have multiple “await” inside the try block only the first exception will be handled and the next “await” would not be reached. If we want all the methods to be called even some one throw exception we have to call them without “await” keyword and wait for all the tasks using Task.WhenAll method.

如果在try代碼塊中有多個await,則僅第一個異常會被捕獲,下一個await將不會執行。如果我們想讓所有的方法都被調用,哪怕會拋異常,我們必須不能使用await調用,並且用Task.WhenAll方法等待它們

 1         private async static void CallWithAsync()
 2               {
 3                  try
 4                    {
 5 
 6                        Task<string> t1 = GreetingAsync("Bulbul");
 7 
 8                       Task<string> t2 = GreetingAsync("Ahmed");
 9 
10                       await Task.WhenAll(t1, t2);
11                   }
12                catch (Exception ex)
13                {
14                Console.WriteLine(&ldquo;handled {0}&rdquo;, ex.Message);
15              }
16        }

Although all tasks will be completed, we can see exception only from first task. It’s not the task that threw the exception first, but the first task in the list.

One way to get the error from all the tasks is to declare them outside the try block so that the can be accessed from exception block and then check the “IsFaulted” property of the task. If it has an exception then the “IsFaulted” property will be true. And then we can get the exception by the inner exception of the task instances.

雖然所有的任務都會被執行,但是我們只能看到第一個任務的異常。不是拋出異常的第一個任務,而是列表中的第一個任務。

獲取所有任務異常的一種方法,是在try代碼塊外定義任務,在exception代碼塊中就能訪問他們,並檢查任務的IsFaulted屬性。如果有異常,則IsFaulted值為True。那么我們可以通過Task的內部異常屬性得到異常信息。

But there is another better way like this:

但是有另一種更好的方法:

 1         static async void ShowAggregatedException()
 2            {
 3               Task taskResult = null;
 4               try 
 5              {
 6                   Task<string> t1 = GreetingAsync("Bulbul");
 7                   Task<string> t2 = GreetingAsync("Ahmed");
 8                   await (taskResult = Task.WhenAll(t1, t2));
 9            }
10           catch (Exception ex)
11           {
12              Console.WriteLine("handled {0}", ex.Message);
13              foreach (var innerEx in taskResult.Exception.InnerExceptions)
14             {
15                Console.WriteLine("inner exception {0}", nnerEx.Message);
16            }
17         }
18   }

Canceling the Task(取消任務)

Previously if we used thread from ThreadPool, it was not possible to cancel the thread. Now Task class provides a way to cancel the started task based on the CancellationTokenSource class, Steps to cancel a task:

  1. The asynchronous method should except a parameter of type “CancellationToken
  2. Create an instance of CancellationTokenSource class like:
  3. Pass the CancellationToken from the instace to the asynchronous method, like:
  4. From the long running method, we have to call ThrowIfCancellationRequested() method ofCancellationToken.
  5. Catch the OperationCanceledException from where we are awiting for the Task.
  6. Now if we cancel the operation by calling Cancel method of instance of CancellationTokenSource, OperationCanceledException will be thrown from the long running operation. We can set time to cancel the operation to the instanc also. For more detail about CancellationTokenSource class please see following link:https://msdn.microsoft.com/en-us/library/system.threading.cancellationtokensource%28v=vs.110%29.aspx

以前如果我們使用線程池的線程,是不可能取消的。現在Task類提供了一種基於CancellationTokenSource類的取消已啟動線程的方法。

取消一個任務的步驟:

  1. 異步方法必須包含一個 CancellationToken的參數(原文是不包括?)
  2. 創建一個CancellationTokenSource 類的實例:
1                     var cts = new CancellationTokenSource();
  1. 將實例的CancellationToken 傳入異步方法,如:
1    Task<string> t1 = GreetingAsync("Bulbul", cts.Token);
  1. 在長時間運行的方法中,我們需要調用CancellationToken的ThrowIfCancellationRequested()方法
1                   static string Greeting(string name, CancellationToken token)
2                     {
3                        Thread.Sleep(3000);
4                        token. ThrowIfCancellationRequested();
5                       return string.Format("Hello, {0}", name);
6                  }
  1. 在等待任務的地方捕獲OperationCanceledException異常
  2.  如果我們通過調用CancellationTokenSource實例的Cancel方法來取消操作,那么長時間運行的方法將會拋OperationCanceledException 異常。我們也可以設置時間取消操作。更多關於CancellationTokenSource 類的細節,請看下面的鏈接:https://msdn.microsoft.com/en-us/library/system.threading.cancellationtokensource%28v=vs.110%29.aspx

Let us see the whole things in an example code, in this example we are canceling the operation after one second:

讓我們在例子中看下整個流程,這個例子我們在一秒后取消操作。

 1 static void Main(string[] args)
 2         {
 3             CallWithAsync();
 4             Console.ReadKey();           
 5         }
 6 
 7         async static void CallWithAsync()
 8         {
 9             try
10             {
11                 CancellationTokenSource source = new CancellationTokenSource();
12                 source.CancelAfter(TimeSpan.FromSeconds(1));
13                 var t1 = await GreetingAsync("Bulbul", source.Token);
14             }
15             catch (OperationCanceledException ex)
16             {
17                 Console.WriteLine(ex.Message);
18             }
19         }
20 
21         static Task<string> GreetingAsync(string name, CancellationToken token)
22         {
23             return Task.Run<string>(() =>
24             {
25                 return Greeting(name, token);
26             });
27         }
28 
29         static string Greeting(string name, CancellationToken token)
30         {
31             Thread.Sleep(3000);
32             token.ThrowIfCancellationRequested();
33             return string.Format("Hello, {0}", name);
34         }

Parallel programming(並行編程)

.NET 4.5 and above has introduced a class called “Parallel”, an abstraction over the thread class. Using the “Parallel” class we can implement parallelism. Parallelism differs from the Threading in a way that it uses all the available CPU or core. Two type of parallelism is possible,

.NET 4.5及以上版本介紹了一個對Thread類的抽象Parallel類。用Parallel類我們可以實現並行。並行不同於線程的方式,它使用所有可用的CPU和核心。兩種可能的並行:

  1. Data Parallelism: If we have a big collection of data and we want some operation on each of the data to perform parallely then we can use data parallelism. Parallel class has static For or ForEach method to perform data parallelism, like

數據並行:如果我們有一個大數據的集合,想要每一個數據並行的執行一些操作,可以使用數據並行。Parallel類有靜態的For 或 ForEach方法執行數據並行,如:

1              ParallelLoopResult result =
2                     Parallel.For(0, 100, async (int i) =>
3                     {
4                         Console.WriteLine("{0}, task: {1}, thread: {2}", i,
5                         Task.CurrentId, Thread.CurrentThread.ManagedThreadId);
6                         await Task.Delay(10);
7                        
8               });

Parallel For or ForEach may use several threads and the index (in the code i) is not sequential.

If we want to stop parallel For o ForEach method earlier we may pass ParallelLoopState as a parameter and based on the state we can break the loop.

Parallel For 或ForEach 可能用幾個線程,並且索引不是順序的(代碼中的i)

如果我們想要早些停止Parallel For或ForEach方法,我們可以傳遞參數ParallelLoopState,基於這個狀態,我們可以跳出循環。

1         ParallelLoopResult result =
2                     Parallel.For(0, 100, async (int i, ParallelLoopState pls) =>
3                     {
4                         Console.WriteLine("{0}, task: {1}, thread: {2}", i,
5                         Task.CurrentId, Thread.CurrentThread.ManagedThreadId);
6                         await Task.Delay(10);
7                         if (i > 5) pls.Break();
8               });

Be careful while breaking the loop, as it is running in several threads may run larger than the break point. We should not take any decision based on the break point.

跳出循環時需要注意,它運行在多個線程中,可能會運行的比break點 大(代碼中的i 可能大於5)。我們不能根據跳出點做任何決定。

  1. Task Parallelism: If we want to run multiple task in parallel we can use task parallelism by calling the invoke method of Parallel class. Parallel.Invoke method accepts an array of Action delegate. For example:

並行任務:如果我們想並行的運行多個任務,我們可以調用Parallel類的invoke方法使用任務並行。Parallel.Invoke方法接收一個Action委托的數組。例如:

1                static void ParallelInvoke()
2                 {
3                     Parallel.Invoke(MethodOne, MethodTwo);
4 
5                }

Conclusion(結論)

I have tried to introduce asynchronous programming technique that .NET framework 4.5 provided. I have tried to keep the things simple and did not go into advanced detail. Many of the examples and references are taken from the "Professional C# 2012 and .NET 4.5 of Wrox".

試着介紹.NET framework 4.6提供的異步編程技術。試着把事情簡單化,並沒有深入到細節中。許多例子和引用來自“Professional C# 2012 and .NET 4.5 of Wrox”。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM