zoukankan      html  css  js  c++  java
  • Task Parallel Library02,更进一步

    前一篇中,了解了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";
    
                });
    
            }
    

    1

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

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

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

    2

    但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);
    
            }
    
  • 相关阅读:
    有序数组中找中位数
    卡特兰数 catalan number
    海量数据等概率选取问题
    求字符串中最长无重复字符的子串
    Linux的进程通信(IPC)
    Linux多线程编程
    后缀数组处理字符串的利器
    网络编程socket基本API详解
    Windows线程的创建与终止
    《算法导论》读书笔记之第10章 基本数据结构之二叉树
  • 原文地址:https://www.cnblogs.com/darrenji/p/4438706.html
Copyright © 2011-2022 走看看