多线程编程-按完成顺序返回结果

按完成顺序返回结果

static void Main(string[] args)
{
    
    Console.WriteLine("TTTTT: 数据返回时,显示页面长度");
    var task = ShowPageLengthTaskAsync("https://www.cnblogs.com/trust-freedom/p/12002089.html", "http://csharpindepth.com", "https://www.cnblogs.com/chenhuabin/p/11369359.html", "https://www.cnblogs.com/trust-freedom/p/11934262.html");
    var total = task.GetAwaiter().GetResult();
    Console.WriteLine("Total Length: {0}", total);
    Console.WriteLine("TTTTT: 结束啦!!!");

    Console.ReadKey();
}

private static async Task<int> ShowPageLengthTaskAsync(params string[] urls)
{
    try
    {
        var tasks = urls.Select(async url =>
        {
            using (var client = new HttpClient())
            {
                return await client.GetStringAsync(url);
            }
        }).ToList();
        int total = 0;
        foreach (var item in tasks.IncompletionOrder())
        {
            string page = await item;
            Console.WriteLine("Get Page Lenght: {0}", page.Length);
            total += page.Length;
        }
        return total;
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
        return -1;
    }
}
/// <summary>
/// 按完成的顺序将任务序列转换到新的集合
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="source">一般顺序的任务集合</param>
/// <returns>所得结果按完成的顺序排序</returns>
public static IEnumerable<Task<T>> IncompletionOrder<T>(this IEnumerable<Task<T>> source)
{
    var inputs = source.ToList();
    var boxes = inputs.Select(s => new TaskCompletionSource<T>()).ToList();
    int curIndx = -1;
    foreach (var item in inputs)
    {
        item.ContinueWith(completed =>
        {
            var nextBox = boxes[Interlocked.Increment(ref curIndx)];
            PropagateResult(completed, nextBox);
        }, TaskContinuationOptions.ExecuteSynchronously);
    }
    return boxes.Select(s => s.Task);
}
/// <summary>
/// 将给定任务的状态传播到源
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="completedTask">已经完成的任务</param>
/// <param name="source">任务完成的源</param>
private static void PropagateResult<T>(Task<T> completedTask, TaskCompletionSource<T> source)
{
    switch (completedTask.Status)
    {
        case TaskStatus.RanToCompletion:
            source.TrySetResult(completedTask.Result);
            break;
        case TaskStatus.Canceled:
            source.TrySetCanceled();
            break;
        case TaskStatus.Faulted:
            source.TrySetException(completedTask.Exception.InnerException);
            break;
        default:
            throw new ArgumentException("任务未完成!");
    }
}     

posted @ 2019-11-25 13:44  wesson2019  阅读(310)  评论(0编辑  收藏  举报