Task2
这篇文章是第一篇Task文章的继续,比较啰嗦,本人也是靠msdn文档来学习的;
一、罗列一些属性
1、TaskCanceledException 类 ,表示一个用于告知任务取消的异常。https://msdn.microsoft.com/zh-cn/library/system.threading.tasks.taskcanceledexception(v=vs.110).aspx
2、TaskContinuationOptions Flag枚举,创建的任务指定行为,https://msdn.microsoft.com/zh-cn/library/system.threading.tasks.taskcontinuationoptions(v=vs.110).aspx
3、TaskCreationOptions Flag枚举,指定用于控制任务的创建和执行的可选行为的标志。https://msdn.microsoft.com/zh-cn/library/system.threading.tasks.taskcreationoptions(v=vs.110).aspx
4、TaskStatus 枚举,表示 Task的生命周期中的当前阶段。https://msdn.microsoft.com/zh-cn/library/system.threading.tasks.taskstatus(v=vs.110).aspx
二、UnWrap 创建一个代理 Task 表示异步操作的 TryExecuteTaskInline。展开,解包,如返回值是Task<Task<int>>==>Task<int>
1 // Invoking individual tasks is straightforward 2 Task<int> t1 = RemoteIncrement(0); 3 Console.WriteLine("Started RemoteIncrement(0)"); 4 5 // Chain together the results of (simulated) remote operations. 6 // The use of Unwrap() instead of .Result below prevents this thread from blocking while setting up this continuation chain. 7 Task<int> t2 = RemoteIncrement(4) 8 // RemoteIncrement() returns Task<int> so no unwrapping is needed for the first continuation. 9 .ContinueWith(t => RemoteIncrement(t.Result)) 10 // ContinueWith() returns Task<Task<int>>. Therefore unwrapping is needed. 11 .Unwrap().ContinueWith(t => RemoteIncrement(t.Result)) 12 .Unwrap().ContinueWith(t => RemoteIncrement(t.Result)) // and on it goes... 13 .Unwrap(); 14 Console.WriteLine("Started RemoteIncrement(...(RemoteIncrement(RemoteIncrement(4))...)"); 15 16 try 17 { 18 t1.Wait(); 19 Console.WriteLine("Finished RemoteIncrement(0)\n"); 20 21 t2.Wait(); 22 Console.WriteLine("Finished RemoteIncrement(...(RemoteIncrement(RemoteIncrement(4))...)"); 23 } 24 catch (AggregateException e) 25 { 26 Console.WriteLine("A task has thrown the following (unexpected) exception:\n{0}", e); 27 } 28 29 Console.ReadKey(); 30 //结果: 31 //Started RemoteIncrement(0) 32 //Started RemoteIncrement(...(RemoteIncrement(RemoteIncrement(4))...) 33 //Thread=10, Next=1 34 //Finished RemoteIncrement(0) 35 36 //Thread=11, Next=5 37 //Thread=12, Next=6 38 //Thread=11, Next=7 39 //Thread=10, Next=8 40 //Finished RemoteIncrement(...(RemoteIncrement(RemoteIncrement(4))...)
三、TaskCompletionSource
TaskCompletionSource 表示未绑定到委托的 Task<TResult> 的制造者方,并通过 Task 属性提供对使用者方的访问值并且通过TrySetResult方法可以设置Task的返回值。 task.IsFaulted 只有在ContinueWith里面才会等待任务执行完
1 static public class Connector 2 { 3 /// <summary> 4 /// begin connect 5 /// </summary> 6 /// <param name="endPoint"></param> 7 /// <exception cref="ArgumentNullException">endPoint is null</exception> 8 static public Task<Socket> Connect(EndPoint endPoint) 9 { 10 if (endPoint == null) throw new ArgumentNullException("endPoint"); 11 12 var source = new TaskCompletionSource<Socket>(); 13 var socket = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp); 14 15 var e = new SocketAsyncEventArgs(); 16 e.UserToken = new Tuple<TaskCompletionSource<Socket>, Socket>(source, socket); 17 e.RemoteEndPoint = endPoint; 18 e.Completed += OnCompleted; 19 20 bool completed = true; 21 try { completed = socket.ConnectAsync(e); } 22 catch (Exception ex) { source.TrySetException(ex); } 23 if (!completed) ThreadPool.QueueUserWorkItem(_ => OnCompleted(null, e)); 24 25 return source.Task; 26 } 27 /// <summary> 28 /// connect completed 29 /// </summary> 30 /// <param name="sender"></param> 31 /// <param name="e"></param> 32 static private void OnCompleted(object sender, SocketAsyncEventArgs e) 33 { 34 var t = e.UserToken as Tuple<TaskCompletionSource<Socket>, Socket>; 35 var source = t.Item1; 36 var socket = t.Item2; 37 var error = e.SocketError; 38 39 e.UserToken = null; 40 e.Completed -= OnCompleted; 41 e.Dispose(); 42 43 if (error != SocketError.Success) 44 { 45 socket.Close(); 46 source.TrySetException(new SocketException((int)error)); 47 return; 48 } 49 50 source.TrySetResult(socket); 51 } 52 }
1 TaskCompletionSource<int> tcs1 = new TaskCompletionSource<int>(); 2 Task<int> t1 = tcs1.Task; 3 // Start a background task that will complete tcs1.Task 4 Task.Factory.StartNew(() => 5 { 6 Thread.Sleep(2000); 7 tcs1.TrySetResult(15); 8 }); 9 // The attempt to get the result of t1 blocks the current thread until the completion source gets signaled. 10 // It should be a wait of ~2000 ms. 11 Stopwatch sw = Stopwatch.StartNew(); 12 int result = t1.Result;//获取结果的时候必须等待操作完成 13 sw.Stop(); 14 Console.WriteLine("(ElapsedTime={0}): t1.Result={1} (expected 15) ", sw.ElapsedMilliseconds, result); 15 16 // Alternatively, an exception can be manually set on a TaskCompletionSource.Task 17 TaskCompletionSource<int> tcs2 = new TaskCompletionSource<int>(); 18 Task<int> t2 = tcs2.Task; 19 20 // Start a background Task that will complete tcs2.Task with an exception 21 Task.Factory.StartNew(() => 22 { 23 Thread.Sleep(1000); 24 25 //tcs2.SetException(new InvalidOperationException("SIMULATED EXCEPTION")); 26 //出现了异常,已被系统处理,但是下面获取Result属性的时候肯定出错 27 tcs2.TrySetException(new InvalidOperationException("SIMULATED EXCEPTION")); 28 }); 29 30 // The attempt to get the result of t2 blocks the current thread until the completion source gets signaled with either a result or an exception. 31 // In either case it should be a wait of ~1000 ms. 32 //sw = Stopwatch.StartNew(); 33 //解决异常1 调用 Task 的 Wait或者 Task.Result 方法时使用 try-catch 捕获异常: 34 //try 35 //{ 36 // result = t2.Result;//因为TrySetException,获取结果会抛错 37 38 // Console.WriteLine("t2.Result succeeded. THIS WAS NOT EXPECTED."); 39 //} 40 //catch (AggregateException e) 41 //{ 42 // Console.Write("(ElapsedTime={0}): ", sw.ElapsedMilliseconds); 43 // Console.WriteLine("The following exceptions have been thrown by t2.Result: (THIS WAS EXPECTED)"); 44 // for (int j = 0; j < e.InnerExceptions.Count; j++) 45 // { 46 // Console.WriteLine("\n-------------------------------------------------\n{0}", e.InnerExceptions[j].ToString()); 47 // } 48 //} 49 50 //解决异常2 在 Task 的 ContinueWith 方法中读取 Task 的 IsFaulted 属性是否出错: 51 t2.ContinueWith(task => 52 { 53 //task是上一个任务的结果, task.IsFaulted是判断有没有错误;如果不在ContinueWith里面或者在外面不用T2.Wait执行完,结果可能不 54 //正确,因为IsFaulted属性不会阻塞线程的, 直接判断任务代码还没出现错误都是false,没有出错 55 if (task.IsFaulted) 56 { 57 Console.WriteLine(task.Exception.GetBaseException()); 58 Console.WriteLine("出现了异常,已被系统处理,但是获取Result属性的时候肯定出错"); 59 Console.WriteLine(task.Result); 60 } 61 else 62 { 63 //没有异常才获取结果,要不然会抛错 64 Console.WriteLine(task.Result); 65 } 66 }); 67 Console.ReadKey();
四、TaskFactory
在大多数情况下,我们无需实例化一个新 TaskFactory 实例。 相反,可以使用 Task.Factory 属性,它返回一个工厂对象,将使用默认值。 然后可以调用其方法来启动新任务或定义任务延续。
//想等待多个任务就用Task数组,使用Task.Await或者Task.Factory.ContinueWhenAll()
//创建一个任务,在数组中的任务之一通过调用完成后开始 ContinueWhenAny 方法。
//创建一个任务,在数组中的所有任务已都完成通过调用开始 ContinueWhenAll 方法。
1 //TaskFactory 类 2 Task[] tasks = new Task[2]; 3 String[] files = null; 4 String[] dirs = null; 5 String docsDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); 6 tasks[0] = Task.Factory.StartNew(() => { Thread.Sleep(3000); files = Directory.GetFiles(docsDirectory); }); 7 tasks[1] = Task.Factory.StartNew(() => dirs = Directory.GetDirectories(docsDirectory)); 8 Console.WriteLine(files.Length);//不会等待的,报空异常 9 Task.Factory.ContinueWhenAll(tasks, completedTasks => 10 { 11 Console.WriteLine("{0} contains: ", docsDirectory); 12 Console.WriteLine(" {0} subdirectories", dirs.Length); 13 Console.WriteLine(" {0} files", files.Length); 14 }); 15 Console.ReadKey();
Task<string[]>[] tasks = new Task<string[]>[2]; string docsDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); tasks[0] = Task<string[]>.Factory.StartNew(() => Directory.GetFiles(docsDirectory)); tasks[1] = Task<string[]>.Factory.StartNew(() => Directory.GetDirectories(docsDirectory)); Task.Factory.ContinueWhenAll(tasks, completedTasks => { Console.WriteLine("{0} contains: ", docsDirectory); Console.WriteLine(" {0} subdirectories", tasks[1].Result.Length); Console.WriteLine(" {0} files", tasks[0].Result.Length); }); Console.ReadKey();