正文

.Net中Task Parallel Library的进阶用法(.net task 多线程)太疯狂了

文章摘要

这篇文章介绍了C#中`Task`类的使用方法,重点讨论了如何获取`Task`的返回值以及如何控制任务的执行过程。文章详细阐述了以下几点: 1. **Task的Result属性**:`Task<T>`的`Result`属性可以获取任务的返回值,但获取过程会阻塞线程。 2. **ContinueWith方法**:可以不阻塞线程,通过`ContinueWith`方法在某个线程结束之后继续执行后续代码。该方法还可以根据任务的状态(成功或失败)处理结果或异常。 3. **TaskContinuationOptions参数**:可以通过`TaskContinuationOptions`参数控制`ContinueWith`方法的行为,例如在任务成功时处理结果或在任务失败时处理异常。 4. **Task.IsCompleted属性**:可以使用`IsCompleted`属性判断任务是否完成,并通过`ContinueWith`方法进一步处理未完成的任务。 5. **Task.Status属性**:结合`Task.Status`属性和`TaskStatus`枚举,可以判断任务的状态(例如运行完成、被取消或发生错误)。 6. **TaskCompletionSource**:可以通过`TaskCompletionSource<T>`手动设置任务的结果,并在任务完成时获取结果。 7. **.NET 4.5以上版本**:引入了`Task`的`FromResult`静态方法,可以直接返回指定类型的`Task`。 文章通过示例代码说明了如何使用上述方法,帮助读者理解如何在异步编程中有效管理任务的执行和状态。



在前一篇中,了解了Task的基本用法

如果一个方法返回Task,Task<T>,如何获取Task的返回值,获取值的过程会阻塞线程吗?

static void Main(string[] args) { var result=DoWorkAsync().Result; Console.WriteLine(result); Console.WriteLine(“我会什么时候显示”); Console.ReadKey(); } static Task<string> DoWorkAsync() { return Task<string>.Factory.StartNew(()=> { Thread.Sleep(3000); return “hello”; }); }

可见,Task的Result属性可以获取返回值,而且,获取返回值的过程线程是被阻塞的。

是否可以不阻塞线程,又能拿到某个线程的返回值呢?ContinueWith方法在某个线程结束之后进行,但同时不会阻塞线程。

static void Main(string[] args) { DoWorkAsync().ContinueWith((pre)=> { Console.WriteLine(pre.Result); }); Console.WriteLine(“我会什么时候显示”); Console.ReadKey(); }

但ContinueWith总会在某个线程结束之后进行,是否可以对ContinueWith的过程控制一下呢?

static void Main(string[] args) { DoWorkAsync().ContinueWith((pre)=> { Console.WriteLine(pre.Result); }, TaskContinuationOptions.NotOnFaulted); DoWorkAsync().ContinueWith((pre)=> { Console.WriteLine(pre.Exception); },TaskContinuationOptions.OnlyOnFaulted); Console.WriteLine(“我会什么时候显示”); Console.ReadKey(); }

以上,当没有错误的时候就把返回值显示出来,有错误就把错误信息显示出来。

还可以通过Task的实例方法IsCompleted来判断一个线程是否完成。

static void Main(string[] args) { var doWorkTask=DoWorkAsync(); if (doWorkTask.IsCompleted) { Console.WriteLine(doWorkTask.Result); } else { doWorkTask.ContinueWith((pre)=> { Console.WriteLine(pre.Result); }, TaskContinuationOptions.NotOnFaulted); doWorkTask.ContinueWith((pre)=> { Console.WriteLine(pre.Exception); }, TaskContinuationOptions.OnlyOnFaulted); } Console.WriteLine(“我会什么时候显示”); Console.ReadKey(); }

Task的Status属性,以及结合TaskStatus枚举,可以判断Task的状态。

static void Main(string[] args) { var httpClient=new HttpClient(); Task<string> baiduTask=httpClient.GetStringAsync(“http://www.baidu.com”); var httpClient2=new HttpClient(); Task<string> sinaTask=httpClient2.GetStringAsync(“http://www.sina.com.cn”); //等上面2个任务完成时这里再开始 Task<string[]> task=Task.WhenAll(baiduTask, sinaTask); task.ContinueWith(stringArray=> { //如果任务完成 if (task.Status==TaskStatus.RanToCompletion) { for (int i=0; i < stringArray.Result.Length;i++) { Console.WriteLine(stringArray.Result[i].Substring(0,100)); } } else if (task.Status==TaskStatus.Canceled) //如果被取消 { Console.WriteLine(“{0}这个任务被取消了”,task.Id); } else //发生错误 { Console.WriteLine(“发生错误了~~”); foreach (var item in task.Exception.InnerExceptions) { Console.WriteLine(item.Message); } } }); Console.ReadKey(); }

如果要控制Task的生命周期,可以考虑使用TaskCompletionSource<T>。

static void Main(string[] args) { AsyncFactory.GetIntAsync().ContinueWith((prev)=> { if (prev.Status==TaskStatus.RanToCompletion) { Console.WriteLine(prev.Result); } else if (prev.Status==TaskStatus.Canceled) { Console.WriteLine(“任务被取消”); } else { Console.WriteLine(“发生错误哦”); Console.WriteLine(prev.Exception); } }); Console.ReadKey(); } } public static class AsyncFactory { public static Task<int> GetIntAsync() { var tsc=new TaskCompletionSource<int>(); var timer=new System.Timers.Timer(2000); timer.AutoReset=false; timer.Elapsed +=(s, e)=> { tsc.SetResult(10); timer.Dispose(); }; timer.Start(); return tsc.Task; } }

以上,通过TaskCompletionSource<T>的SetResult给线程设置返回值,通过TaskCompletionSource<T>的.Task有获取了线程。

另外,从.NET 4.5开始,Task的静态方法FromResult,接收T类型,返回Task<T>。

static void Main(string[] args) { var intTask=GetIntAsync(); if (intTask.Status==TaskStatus.RanToCompletion) { Console.WriteLine(intTask.Result); } else if (intTask.Status==TaskStatus.Canceled) { Console.WriteLine(“任务被取消”); } else { Console.WriteLine(“发生错误哦”); Console.WriteLine(intTask.Exception); } Console.ReadKey(); } static Task<int> GetIntAsync() { return Task.FromResult(10); }

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对脚本之家的支持。如果你想了解更多相关内容请查看下面相关链接

您可能感兴趣的文章:.Net中Task Parallel Library的基本用法ASP.NET?Core在Task中使用IServiceProvider的问题解析.Net通过TaskFactory.FromAsync简化APM.NET中的async和await关键字使用及Task异步调用实例