C#当中的多线程_任务并行库(中)

发现自己有点懒了!也可能是越往后越难了,看书理解起来有点费劲,所以这两天就每天更新一点学习笔记吧。

4.5 将APM模式转化为任务

书上提供的三种方式

方式一:

1  class Program
2         {
3                 //定义一个委托
4                 private delegate string AsynchronousTask(string threadName);
5
6                 static void Main(string[] args)
7                 {
8                         //实例化一个委托对象,绑定Test函数
9                         AsynchronousTask d = Test;
10
11                       Console.WriteLine("Option 1");
12                       //调用TaskFactory<TResult> Factory.FromAsync()方法,这个方法有很多重载函数
13                       //这个方法是 public Task<TResult> FromAsync(IAsyncResult asyncResult, Func<IAsyncResult, TResult> endMethod);
14                       Task<string> task = Task<string>.Factory.FromAsync(
15                       d.BeginInvoke("AsyncTaskThread", Callback, "a delegate asynchronous call"), d.EndInvoke);
16                       //绑定任务执行完的后续操作
17                       task.ContinueWith(t => Console.WriteLine("Callback is finished, now running a continuation! Result: {0}",
18                                 t.Result));
19
20                         //循环打印状态信息
21                         while (!task.IsCompleted)
22                         {
23                                 Console.WriteLine(task.Status);
24                                 Thread.Sleep(TimeSpan.FromSeconds(0.5));
25                         }
26                         Console.WriteLine(task.Status);
27                         Thread.Sleep(TimeSpan.FromSeconds(1));
28
29                         Console.WriteLine("----------------------------------------------");
30                         Console.WriteLine();
31                 }
32
33                 //定义一个回调函数
34                 private static void Callback(IAsyncResult ar)
35                 {
36                         Console.WriteLine("Starting a callback...");
37                         Console.WriteLine("State passed to a callbak: {0}", ar.AsyncState);
38                         Console.WriteLine("Is thread pool thread: {0}", Thread.CurrentThread.IsThreadPoolThread);
39                         Console.WriteLine("Thread pool worker thread id: {0}", Thread.CurrentThread.ManagedThreadId);
40                 }
41
42                 //定义一个委托函数
43                 private static string Test(string threadName)
44                 {
45                         Console.WriteLine("Starting...");
46                         Console.WriteLine("Is thread pool thread: {0}", Thread.CurrentThread.IsThreadPoolThread);
47                         Thread.Sleep(TimeSpan.FromSeconds(2));
48                         Thread.CurrentThread.Name = threadName;
49                         return string.Format("Thread name: {0}", Thread.CurrentThread.Name);
50                 }

方式二:

与方式一差不多,但是使用了TaskFactory<TResult> Factory.FromAsync()方法的另一种重载,该重载并不允许指定一个将会在异步委托调用后被调用的回调函数。但是可以使用后续操作替代它。如果回调函数非常重要,建议使用第一种。

1  class Program
2         {
3                 //定义一个委托
4                 private delegate string AsynchronousTask(string threadName);
5
6                 static void Main(string[] args)
7                 {
8                          //实例化一个委托对象,绑定Test函数
9                          AsynchronousTask d = Test;
10
11                        Console.WriteLine("Option 2");
12                        //调用TaskFactory<TResult> Factory.FromAsync()方法,这个方法有很多重载函数
13                        /*
14                         * 这个方法重载是
15                         * public Task<TResult> FromAsync<TArg1>(Func<TArg1, AsyncCallback, object, IAsyncResult> beginMethod,
16                         * Func<IAsyncResult, TResult> endMethod,
17                         * TArg1 arg1,
18                         * object state);
19                         */
20                       Task<string> task= Task<string>.Factory.FromAsync(d.BeginInvoke,d.EndInvoke,
21                                                                                                     "AsyncTaskThread",
22                                                                                                     "a delegate asynchronous call");
23                                 
24                         //绑定任务执行完的后续操作
25                       task.ContinueWith(t => Console.WriteLine("Task is completed, now running a continuation! Result: {0}",
26                               t.Result));
27
28                         //循环打印状态信息
29                         while (!task.IsCompleted)
30                         {
31                                 Console.WriteLine(task.Status);
32                                 Thread.Sleep(TimeSpan.FromSeconds(0.5));
33                         }
34                         Console.WriteLine(task.Status);
35                         Thread.Sleep(TimeSpan.FromSeconds(1));
36
37                         Console.WriteLine("----------------------------------------------");
38                         Console.WriteLine();
39                 }
40
41                 //定义一个委托函数
42                 private static string Test(string threadName)
43                 {
44                         Console.WriteLine("Starting...");
45                         Console.WriteLine("Is thread pool thread: {0}", Thread.CurrentThread.IsThreadPoolThread);
46                         Thread.Sleep(TimeSpan.FromSeconds(2));
47                         Thread.CurrentThread.Name = threadName;
48                         return string.Format("Thread name: {0}", Thread.CurrentThread.Name);
49                 }

方式三:

1  class Program
2         {
3                 private delegate string IncompatibleAsynchronousTask(out int threadId);
4
5                 static void Main(string[] args)
6                 {
7                         int threadId;
8                         IncompatibleAsynchronousTask e = Test;
9
10                         Console.WriteLine("Option 3");
11                         
12                         IAsyncResult ar = e.BeginInvoke(out threadId, Callback, "a delegate asynchronous call");
13
14                         /*这是一个小技巧,EndMethod使用了out参数,与FromAsync的方法重载并不兼容。
15                          * 然而,可以很轻松地将EndMethod调用封装到一个lambda表达式当中,从而适合
16                          * 工厂方法。
17                          */
18                         Task<string> task = Task<string>.Factory.FromAsync(ar, _ => e.EndInvoke(out threadId, ar));
19                         task.ContinueWith(t =>
20                                 Console.WriteLine("Task is completed, now running a continuation! Result: {0}, ThreadId: {1}",
21                                         t.Result, threadId));
22
23                         while (!task.IsCompleted)
24                         {
25                                 Console.WriteLine(task.Status);
26                                 Thread.Sleep(TimeSpan.FromSeconds(0.5));
27                         }
28                         Console.WriteLine(task.Status);
29
30                         Thread.Sleep(TimeSpan.FromSeconds(1));
31                 }
32
33                 private static void Callback(IAsyncResult ar)
34                 {
35                         Console.WriteLine("Starting a callback...");
36                         Console.WriteLine("State passed to a callbak: {0}", ar.AsyncState);
37                         Console.WriteLine("Is thread pool thread: {0}", Thread.CurrentThread.IsThreadPoolThread);
38                         Console.WriteLine("Thread pool worker thread id: {0}", Thread.CurrentThread.ManagedThreadId);
39                 }
40
41                 private static string Test(out int threadId)
42                 {
43                         Console.WriteLine("Starting...");
44                         Console.WriteLine("Is thread pool thread: {0}", Thread.CurrentThread.IsThreadPoolThread);
45                         Thread.Sleep(TimeSpan.FromSeconds(2));
46                         threadId = Thread.CurrentThread.ManagedThreadId;
47                         return string.Format("Thread pool worker thread id was: {0}", threadId);
48                 }
49  

总结:感觉这个在日常工作当中使用的真的不是很多,比较晦涩难懂,暂且记住有TaskFactory<TResult> Factory.FromAsync()这个方法,通过这个方法可以将APM转化成TPL

4.6 将EAP模式转换成任务

例子先上:

1 class Program
2     {
3         static void Main(string[] args)
4         {
5             //实例化一个TaskCompletionSource<TResult>,它是实现EAP转化成TPL的关键
6             var tcs = new TaskCompletionSource<int>();
7
8             var worker = new BackgroundWorker();
9             worker.DoWork += (sender, eventArgs) =>
10             {
11                 eventArgs.Result = TaskMethod("Background worker", 5);
12             };
13
14             worker.RunWorkerCompleted += (sender, eventArgs) =>
15             {
16                  //如果有错就抛出异常
17                 if (eventArgs.Error != null)
18                 {
19                     tcs.SetException(eventArgs.Error);
20                 }
21                  //如果是取消操作,就取消操作
22                 else if (eventArgs.Cancelled)
23                 {
24                     tcs.SetCanceled();
25                 }
26                 else
27                 {
28                     //正常情况返回结果
29                     tcs.SetResult((int)eventArgs.Result);
30                 }
31             };
32
33             //运行任务
34             worker.RunWorkerAsync();
35
36             //获取结果
37             int result = tcs.Task.Result;
38
39             Console.WriteLine("Result is: {0}", result);
40         }
41
42         static int TaskMethod(string name, int seconds)
43         {
44             Console.WriteLine("Task {0} is running on a thread id {1}. Is thread pool thread: {2}",
45                 name, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread);
46             Thread.Sleep(TimeSpan.FromSeconds(seconds));
47             return 42 * seconds;
48         }

4.7 实现取消选项

我们在前面说过线程工作的取消需要依靠两个类来实现,分别是CancellationTokenSource和CancellationToken这两个类

1     class Program
2     {
3         private static void Main(string[] args)
4         {
5               //定义一个CancellationTokenSource类
6               var cts = new CancellationTokenSource();
7               //创建第一个任务,这里有个很奇怪的第地方,cts.Token被传了两次
8               //分别传给了TaskMethod方法个Task的构造函数,为什么这么做呢?
9               var longTask = new Task<int>(() => TaskMethod("Task 1", 10, cts.Token), cts.Token);
10             //打印任务状态
11             Console.WriteLine(longTask.Status);
12             //取消任务
13             cts.Cancel();
14             //再次打印任务状态
15             Console.WriteLine(longTask.Status);
16             Console.WriteLine("First task has been cancelled before execution");
17
18             //创建第二个任务
19             cts = new CancellationTokenSource();
20             longTask = new Task<int>(() => TaskMethod("Task 2", 10, cts.Token), cts.Token);
21             //启动任务
22             longTask.Start();
23             for (int i = 0; i < 5; i++ )
24             {
25                 Thread.Sleep(TimeSpan.FromSeconds(0.5));
26                 Console.WriteLine(longTask.Status);
27             }
28             //取消任务
29             cts.Cancel();
30             //打印任务状态
31             for (int i = 0; i < 5; i++)
32             {
33                 Thread.Sleep(TimeSpan.FromSeconds(0.5));
34                 Console.WriteLine(longTask.Status);
35             }
36
37             Console.WriteLine("A task has been completed with result {0}.", longTask.Result);
38         }
39
40         private static int TaskMethod(string name, int seconds, CancellationToken token)
41         {
42             Console.WriteLine("Task {0} is running on a thread id {1}. Is thread pool thread: {2}",
43                 name, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread);
44             for (int i = 0; i < seconds; i ++)
45             {
46                 Thread.Sleep(TimeSpan.FromSeconds(1));
47                 //如果任务被取消,就返回-1
48                 if (token.IsCancellationRequested) return -1;
49             }
50             return 42*seconds;
51          }
52    }

cts.Token被传了两次为什么呢?如果在任务实际启动前取消它,该任务的TPL基础设施有责任处理该取消操作,因为这些代码根本不会被执行,通过得到第一个任务的状态可以知道它被取消了。如果尝试对该任务调用Start方法,将会得到InvalidOperationException异常。

解释:

如果在Task构造函数当中取消了,cts.Token这个参数,那么在Cts.Cancel()后面执行longTask.Start(); 会出现什么情况呢?

如下图所示,任务只有在运行操作的时候才能检查到取消操作。所以才会有WaitingToRun这个状态出现。

如果添加了这个参数,结果如下:

这个时候,在取消操作执行完后,执行开始操作就会抛出异常。

时间: 2024-12-16 07:08:22

C#当中的多线程_任务并行库(中)的相关文章

C#当中的多线程_任务并行库(下)

4.8 处理任务中的异常 下面这个例子讨论了任务当中抛出异常,以及任务异常的获取 1     class Program 2     { 3         static void Main(string[] args) 4         { 5             //声明一个任务 6             Task<int> task; 7             //第一种方式,普通的try...catch捕获异常 8             try 9             

使用XE7并行库中的TTask(转)

http://blog.csdn.net/henreash/article/details/41347843 上篇文章学习使用System.Threading单元提供的并行编程和TParallel.For提升循环的执行效率.当需要运行多任务而不是一个循环时,也可以使用并行方式.  使用System.Threading.TTask和System.Threading.ITask可方便的串行执行几个进程.使用TTask类创建任务,使用ITask接口实例管理进程的交互.在代码完成处理前可以使用WaitF

使用XE7并行库中的TTASK.IFUTURE(转)

http://blog.csdn.net/henreash/article/details/41349145 上篇文章讲了使用TTask快速开发同时运行多个任务的应用程序,减少瓶颈.接下来讲解ITask的子接口IFuture. IFuture IFuture给TTask提供了一个机制,让我们可以传递返回特定类型的函数(使用了泛型,类型由<T>决定).使用IFuture实例,运行一个任务,同时让主线程继续执行到我们需要任务运行结果处.使用这种机制可以把代码块按优先级执行,同时也保证在需要的时候获

Delphi XE7中新并行库

Delphi XE7中增加了新的并行库,和.NET的Task和Parellel相似度99%. 具体内容可以看下面的文章: http://www.delphifeeds.com/go/s/119574 如果你熟悉.NET,这个功能并没有大的新意,可对Delphi程序员来说却非常实用.之前要实现多线程,唯一的办法是使用TThread类,而且过程十分繁琐.新的并行库彻底简化了这个过程. 估计下一步就该实现Async和Await异步执行结构了 另外最近Delphi的排名竟然有所上升并且进了前十,对还在用

DELPHI XE7 新的并行库

DELPHI XE7 的新功能列表里面增加了并行库System.Threading, System.SyncObjs. 为什么要增加新的并行库? 还是为了跨平台.以前要并行编程只能从TThread类继承进行多线程处理,大家知道TThread类是从WINDOWS的线程API封装起来的,它封装的是WINDOWS的多线程的东西,是不能脱离WINDOWS的,当然是不能跨平台的.DELPHI现在走的是原生跨平台的道路,一切DELPHI的基础类库都要从只支持WINDOWS改为支持多平台,这是一个庞大而缓慢的

C#5.0之后推荐使用TPL(Task Parallel Libray 任务并行库) 和PLINQ(Parallel LINQ, 并行Linq). 其次是TAP(Task-based Asynchronous Pattern, 基于任务的异步模式)

学习书籍: <C#本质论> 1--C#5.0之后推荐使用TPL(Task Parallel Libray 任务并行库) 和PLINQ(Parallel LINQ, 并行Linq). 其次是TAP(Task-based Asynchronous Pattern, 基于任务的异步模式). --用AggregateException处理Task上的未处理异常. --取消任务. CancellationToken --async修饰方法, 返回Task. task.wait(100)可以阻塞现场. a

多线程_创建线程_继承Thread类

public class ThreadDemo {   public static void main(String[] args){         Demo d = new Demo();   d.start();      for(int i = 0;i < 100;i++){      System.out.println("MainThread" + i);   }   } } class Demo extends Thread {   public void run(

Delphi并行库System.Threading 之ITask 1

不知什么时候,也许是XE8,也许是XE8之前 .Delphi里面多了个System.Threading的并行库. 虽然己经有非常棒的第三方并行库QWorker,但我还是更喜欢官方的东西. 下面是一段使用System.Threading中ITask的代码 procedure TForm3.SpeedButton1Click(Sender: TObject); var tasks: array of ITask; value: Integer; LTask:ITask; X,Y:INTEGER; b

IOS_多线程_售票

H:/1007/01_多线程_大任务_MainViewController.m // MainViewController.m // 多线程-01.大任务 // Created by apple on 13-10-7. #import "MainViewController.h" @interface MainViewController () @property (weak, nonatomic) UIImageView *imageView; @end @implementatio