(译)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”。

转载于:https://www.cnblogs.com/hetring/p/4583306.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值