深入理解 c# 第十五章 显示页面长度当数据返回时 在全部返回时收集结果

   public static partial class TaskExtensions
    {
        public static IEnumerable<Task<T>> InCompletionOrder<T>(this IEnumerable<Task<T>> source)
        {
            var inputs = source.ToList();
            var boxes = inputs.Select(x => new TaskCompletionSource<T>()).ToList();

            int currentIndex = -1;
            foreach (var task in inputs)
            {
                task.ContinueWith(completed =>
				//completed 较长一段
                {
                    var nextBox = boxes[Interlocked.Increment(ref currentIndex)];
					//boxes Count = 3
                    PropagateResult(completed, nextBox);
                }, TaskContinuationOptions.ExecuteSynchronously);
            }
            return boxes.Select(box => box.Task);
        }

        /// <summary> 
        /// Propagates the status of the given task (which must be completed) to a task completion source 
        /// (which should not be). 
        /// </summary> 
        private static void PropagateResult<T>(Task<T> completedTask,
            TaskCompletionSource<T> completionSource)
        {
            switch (completedTask.Status)
			//completedTask很长一段
            {
                case TaskStatus.Canceled:
                    completionSource.TrySetCanceled();
                    break;
                case TaskStatus.Faulted:
                    completionSource.TrySetException(completedTask.Exception.InnerExceptions);
                    break;
                case TaskStatus.RanToCompletion:
                    completionSource.TrySetResult(completedTask.Result);
					//completionSource {System.Threading.Tasks.TaskCompletionSource<string>}
                    break;
                default:
                    // TODO: Work out whether this is really appropriate. Could set 
                    // an exception in the completion source, of course... 
                    throw new ArgumentException("Task was not completed");
            }
        }
    }

    static class MagicOrdering
    {
        static async Task<int> ShowPageLengthsAsync(params string[] urls)
		//urls {string[3]}
        {
            var tasks = urls.Select(async url =>
			//url "http://stackoverflow.com"
            { 
                using (var client = new HttpClient())
				//client {System.Net.Http.HttpClient}
                {
                    return await client.GetStringAsync(url);
                }
            }).ToList();

            int total = 0;
            foreach (var task in tasks.InCompletionOrder())
            {
                string page = await task;
				//page是 html文件的内容
                Console.WriteLine("Got page length {0}", page.Length);
                total += page.Length;
				//total 5216
            }
            return total;
        }

        static void Main() //显示页面长度当数据返回时 在全部返回时收集结果
        {
            var task = ShowPageLengthsAsync("http://stackoverflow.com", "http://www.google.com", "http://csharpindepth.com");
            Console.WriteLine("Total length: {0}", task.Result);
        }
    }


  在全部完成时收集结果
  Task.WhenAll是.NET内置的转换构建块,构建自己的方法。创建InterLeaved方法。
  传递一个输入任务的序列,并返回一个输出任务的序列。两个序列中任务的结果是相同的,但
存在一个差异,即输出任务的完成顺序与输入完全一样,因此可以一次await一个任务,并
可立即得到任务结果。
  依赖TPL中一个非常重要的类型,即TaskCompletionSource<T>。该类型可用于创建一个
尚未含有结果的Task,并在之后提供结果(或异常)。它和AsyncTaskMethodBuilder<T>
都建立在相同的基础结构之上。后者为异步方法提供返回的Task,并在方法体完成时,将
带结果的任务向外传播。
  得到一组URL,并行地对每个URL发起请求,输出任务的顺序会与之相同,并在请求完成
时写下各页面的长度,然后返回总长度。
  
输出
Got page length 5216
Got page length 257025
Exception: System.Reflection.TargetInvocationException: 调用的目标发生了异常。 ---> System.AggregateException: 发生一个 或多个错误。 ---> System.Net.Http.HttpRequestException: 发送请求时出错。 ---> System.Net.WebException: 无法连接到远程服 务器 ---> System.Net.Sockets.SocketException: 由于连接方在一段时间后没有正确答复或连接的主机没有反应,连接尝试失败。 31.13.76.16:80
   在 System.Net.Sockets.Socket.EndConnect(IAsyncResult asyncResult)
   在 System.Net.ServicePoint.ConnectSocketInternal(Boolean connectFailure, Socket s4, Socket s6, Socket& socket, IPAddress& address, ConnectSocketState state, IAsyncResult asyncResult, Exception& exception)
   --- 内部异常堆栈跟踪的结尾 ---
   在 System.Net.HttpWebRequest.EndGetResponse(IAsyncResult asyncResult)
   在 System.Net.Http.HttpClientHandler.GetResponseCallback(IAsyncResult ar)
   --- 内部异常堆栈跟踪的结尾 ---
   在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   在 System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   在 Chapter15.MagicOrdering.<<ShowPageLengthsAsync>b__0>d__2.MoveNext() 位置 省略MagicOrdering.cs:行号 67
--- 引发异常的上一位置中堆栈跟踪的末尾 ---
   在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   在 System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   在 Chapter15.MagicOrdering.<ShowPageLengthsAsync>d__6.MoveNext() 位置 省略MagicOrdering.cs:行号 74
   --- 内部异常堆栈跟踪的结尾 ---
   在 System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)
   在 System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotification)
   在 System.Threading.Tasks.Task`1.get_Result()
   在 Chapter15.MagicOrdering.Main() 位置 MagicOrdering.cs:行号 84
   --- 内部异常堆栈跟踪的结尾 ---
   在 System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
   在 System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments)
   在 System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   在 System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)
   在 MiscUtil.ApplicationChooser.Run(Type type, String[] args)  

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值