个人感觉Task 的WaitAny和WhenAny以及TaskFactory 的ContinueWhenAny有相似的地方,而WaitAll和WhenAll以及TaskFactory 的ContinueWhenAll也是相同,但是WaitAny和WhenAny的返回值有所不同。我们首先来看看Task WhenAny和WhenAll 的实现吧,

public class Task : IThreadPoolWorkItem, IAsyncResult, IDisposable
{
//Creates a task that will complete when any of the supplied tasks have completed.
public static Task<Task> WhenAny(IEnumerable<Task> tasks)
{
if (tasks == null) throw new ArgumentNullException("tasks");
Contract.EndContractBlock();
List<Task> taskList = new List<Task>();
foreach (Task task in tasks)
{
if (task == null) throw new ArgumentException(Environment.GetResourceString("Task_MultiTaskContinuation_NullTask"), "tasks");
taskList.Add(task);
}
if (taskList.Count == )
{
throw new ArgumentException(Environment.GetResourceString("Task_MultiTaskContinuation_EmptyTaskList"), "tasks");
}
// Previously implemented CommonCWAnyLogic() can handle the rest
return TaskFactory.CommonCWAnyLogic(taskList);
} //Creates a task that will complete when all of the supplied tasks have completed.
public static Task<TResult[]> WhenAll<TResult>(params Task<TResult>[] tasks)
{
if (tasks == null) throw new ArgumentNullException("tasks");
Contract.EndContractBlock(); int taskCount = tasks.Length;
if (taskCount == ) return InternalWhenAll<TResult>(tasks); // small optimization in the case of an empty task array Task<TResult>[] tasksCopy = new Task<TResult>[taskCount];
for (int i = ; i < taskCount; i++)
{
Task<TResult> task = tasks[i];
if (task == null) throw new ArgumentException(Environment.GetResourceString("Task_MultiTaskContinuation_NullTask"), "tasks");
tasksCopy[i] = task;
}
return InternalWhenAll<TResult>(tasksCopy);
} private static Task<TResult[]> InternalWhenAll<TResult>(Task<TResult>[] tasks)
{
Contract.Requires(tasks != null, "Expected a non-null tasks array");
return (tasks.Length == ) ? new Task<TResult[]>(false, new TResult[], TaskCreationOptions.None, default(CancellationToken)) : new WhenAllPromise<TResult>(tasks);
} private sealed class WhenAllPromise<T> : Task<T[]>, ITaskCompletionAction
{
private readonly Task<T>[] m_tasks;
private int m_count; internal WhenAllPromise(Task<T>[] tasks) :base()
{
Contract.Requires(tasks != null, "Expected a non-null task array");
Contract.Requires(tasks.Length > , "Expected a non-zero length task array");
m_tasks = tasks;
m_count = tasks.Length;
if (AsyncCausalityTracer.LoggingOn)
AsyncCausalityTracer.TraceOperationCreation(CausalityTraceLevel.Required, this.Id, "Task.WhenAll", ); if (s_asyncDebuggingEnabled)
{
AddToActiveTasks(this);
}
foreach (var task in tasks)
{
if (task.IsCompleted) this.Invoke(task); // short-circuit the completion action, if possible
else task.AddCompletionAction(this); // simple completion action
}
} public void Invoke(Task ignored)
{
if (AsyncCausalityTracer.LoggingOn)
AsyncCausalityTracer.TraceOperationRelation(CausalityTraceLevel.Important, this.Id, CausalityRelation.Join); // Decrement the count, and only continue to complete the promise if we're the last one.
if (Interlocked.Decrement(ref m_count) == 0)
{
T[] results = new T[m_tasks.Length];
List<ExceptionDispatchInfo> observedExceptions = null;
Task canceledTask = null; for (int i = ; i < m_tasks.Length; i++)
{
Task<T> task = m_tasks[i];
Contract.Assert(task != null, "Constituent task in WhenAll should never be null"); if (task.IsFaulted)
{
if (observedExceptions == null) observedExceptions = new List<ExceptionDispatchInfo>();
observedExceptions.AddRange(task.GetExceptionDispatchInfos());
}
else if (task.IsCanceled)
{
if (canceledTask == null) canceledTask = task; // use the first task that's canceled
}
else
{
Contract.Assert(task.Status == TaskStatus.RanToCompletion);
results[i] = task.GetResultCore(waitCompletionNotification: false); // avoid Result, which would triggering debug notification
}
if (task.IsWaitNotificationEnabled) this.SetNotificationForWaitCompletion(enabled: true);
else m_tasks[i] = null; // avoid holding onto tasks unnecessarily
} if (observedExceptions != null)
{
Contract.Assert(observedExceptions.Count > , "Expected at least one exception");
TrySetException(observedExceptions);
}
else if (canceledTask != null)
{
TrySetCanceled(canceledTask.CancellationToken, canceledTask.GetCancellationExceptionDispatchInfo());
}
else
{
if (AsyncCausalityTracer.LoggingOn)
AsyncCausalityTracer.TraceOperationCompletion(CausalityTraceLevel.Required, this.Id, AsyncCausalityStatus.Completed); if (Task.s_asyncDebuggingEnabled)
{
RemoveFromActiveTasks(this.Id);
}
TrySetResult(results);
}
}
Contract.Assert(m_count >= , "Count should never go below 0");
} internal override bool ShouldNotifyDebuggerOfWaitCompletion
{
get
{
return base.ShouldNotifyDebuggerOfWaitCompletion && Task.AnyTaskRequiresNotifyDebuggerOfWaitCompletion(m_tasks);
}
}
}
}

首先我们来看看Task的WhenAny的实现,非常简单调用TaskFactory.CommonCWAnyLogic方法,直接返回Task,而WaitAny【也调用TaskFactory.CommonCWAnyLogic】则需要等待这个Task完成。接下来我们来看看WhenAll的实现,WhenAll核心方法是InternalWhenAll,在InternalWhenAll里面返回了一个WhenAllPromise的Task,WhenAllPromise里面有一个计数器m_count,每当Task完成一个,就调用WhenAllPromise的Invoke方法,实现计数器m_count减1,当计数器m_count为0时表示所有的Task有已经完成。【在Task的WaitAll里面用的是SetOnCountdownMres,和这里的WhenAllPromise相似,都有一个计数器】。

那么我们现在来看看TaskFactory的ContinueWhenAny和ContinueWhenAll的实现

public class TaskFactory
{
public Task ContinueWhenAny<TAntecedentResult>(Task<TAntecedentResult>[] tasks, Action<Task<TAntecedentResult>> continuationAction,
CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
{
if (continuationAction == null) throw new ArgumentNullException("continuationAction");
Contract.EndContractBlock(); StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
return TaskFactory<VoidTaskResult>.ContinueWhenAnyImpl<TAntecedentResult>(tasks, null, continuationAction, continuationOptions, cancellationToken, scheduler, ref stackMark);
}
// Creates a continuation Task<TResult> ,that will be started upon the completion of a set of provided Tasks.
public Task<TResult> ContinueWhenAll<TAntecedentResult>(Task<TAntecedentResult>[] tasks, Func<Task<TAntecedentResult>[], TResult> continuationFunction,
CancellationToken cancellationToken)
{
if (continuationFunction == null) throw new ArgumentNullException("continuationFunction");
Contract.EndContractBlock(); StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
return ContinueWhenAllImpl<TAntecedentResult>(tasks, continuationFunction, null, m_defaultContinuationOptions, cancellationToken, DefaultScheduler, ref stackMark);
} internal static Task<TResult> ContinueWhenAnyImpl<TAntecedentResult>(Task<TAntecedentResult>[] tasks,
Func<Task<TAntecedentResult>, TResult> continuationFunction, Action<Task<TAntecedentResult>> continuationAction,
TaskContinuationOptions continuationOptions, CancellationToken cancellationToken, TaskScheduler scheduler, ref StackCrawlMark stackMark)
{ TaskFactory.CheckMultiTaskContinuationOptions(continuationOptions);
if (tasks == null) throw new ArgumentNullException("tasks");
if (tasks.Length == ) throw new ArgumentException(Environment.GetResourceString("Task_MultiTaskContinuation_EmptyTaskList"), "tasks");
Contract.Requires((continuationFunction != null) != (continuationAction != null), "Expected exactly one of endFunction/endAction to be non-null");
if (scheduler == null) throw new ArgumentNullException("scheduler");
Contract.EndContractBlock(); var starter = TaskFactory.CommonCWAnyLogic(tasks); // Bail early if cancellation has been requested.
if (cancellationToken.IsCancellationRequested
&& ((continuationOptions & TaskContinuationOptions.LazyCancellation) == )
)
{
return CreateCanceledTask(continuationOptions, cancellationToken);
} // returned continuation task, off of starter
if (continuationFunction != null)
{
return starter.ContinueWith<TResult>(
GenericDelegateCache<TAntecedentResult, TResult>.CWAnyFuncDelegate,
continuationFunction, scheduler, cancellationToken, continuationOptions, ref stackMark);
}
else
{
Contract.Assert(continuationAction != null);
return starter.ContinueWith<TResult>(
// Use a cached delegate
GenericDelegateCache<TAntecedentResult,TResult>.CWAnyActionDelegate,
continuationAction, scheduler, cancellationToken, continuationOptions, ref stackMark);
}
}
internal static Task<TResult> ContinueWhenAllImpl<TAntecedentResult>(Task<TAntecedentResult>[] tasks,
Func<Task<TAntecedentResult>[], TResult> continuationFunction, Action<Task<TAntecedentResult>[]> continuationAction,
TaskContinuationOptions continuationOptions, CancellationToken cancellationToken, TaskScheduler scheduler, ref StackCrawlMark stackMark)
{ TaskFactory.CheckMultiTaskContinuationOptions(continuationOptions);
if (tasks == null) throw new ArgumentNullException("tasks"); Contract.Requires((continuationFunction != null) != (continuationAction != null), "Expected exactly one of endFunction/endAction to be non-null");
if (scheduler == null) throw new ArgumentNullException("scheduler");
Contract.EndContractBlock(); Task<TAntecedentResult>[] tasksCopy = TaskFactory.CheckMultiContinuationTasksAndCopy<TAntecedentResult>(tasks); if (cancellationToken.IsCancellationRequested
&& ((continuationOptions & TaskContinuationOptions.LazyCancellation) == )
)
{
return CreateCanceledTask(continuationOptions, cancellationToken);
} var starter = TaskFactory.CommonCWAllLogic(tasksCopy);
if (continuationFunction != null)
{
return starter.ContinueWith<TResult>(
// use a cached delegate
GenericDelegateCache<TAntecedentResult, TResult>.CWAllFuncDelegate,
continuationFunction, scheduler, cancellationToken, continuationOptions, ref stackMark);
}
else
{
Contract.Assert(continuationAction != null); return starter.ContinueWith<TResult>(
// use a cached delegate
GenericDelegateCache<TAntecedentResult, TResult>.CWAllActionDelegate,
continuationAction, scheduler, cancellationToken, continuationOptions, ref stackMark);
}
}
internal static Task<Task<T>[]> CommonCWAllLogic<T>(Task<T>[] tasksCopy)
{
Contract.Requires(tasksCopy != null); // Create a promise task to be returned to the user
CompleteOnCountdownPromise<T> promise = new CompleteOnCountdownPromise<T>(tasksCopy); for (int i = ; i < tasksCopy.Length; i++)
{
if (tasksCopy[i].IsCompleted) promise.Invoke(tasksCopy[i]); // Short-circuit the completion action, if possible
else tasksCopy[i].AddCompletionAction(promise); // simple completion action
} return promise;
}
private sealed class CompleteOnCountdownPromise<T> : Task<Task<T>[]>, ITaskCompletionAction
{
private readonly Task<T>[] _tasks;
private int _count; internal CompleteOnCountdownPromise(Task<T>[] tasksCopy) : base()
{
Contract.Requires((tasksCopy != null) && (tasksCopy.Length > ), "Expected non-null task array with at least one element in it");
_tasks = tasksCopy;
_count = tasksCopy.Length; if (AsyncCausalityTracer.LoggingOn)
AsyncCausalityTracer.TraceOperationCreation(CausalityTraceLevel.Required, this.Id, "TaskFactory.ContinueWhenAll<>", ); if (Task.s_asyncDebuggingEnabled)
{
AddToActiveTasks(this);
}
} public void Invoke(Task completingTask)
{
if (AsyncCausalityTracer.LoggingOn)
AsyncCausalityTracer.TraceOperationRelation(CausalityTraceLevel.Important, this.Id, CausalityRelation.Join); if (completingTask.IsWaitNotificationEnabled) this.SetNotificationForWaitCompletion(enabled: true);
if (Interlocked.Decrement(ref _count) == 0)
{
if (AsyncCausalityTracer.LoggingOn)
AsyncCausalityTracer.TraceOperationCompletion(CausalityTraceLevel.Required, this.Id, AsyncCausalityStatus.Completed); if (Task.s_asyncDebuggingEnabled)
{
RemoveFromActiveTasks(this.Id);
} TrySetResult(_tasks);
}
Contract.Assert(_count >= , "Count should never go below 0");
} internal override bool ShouldNotifyDebuggerOfWaitCompletion
{
get
{
return base.ShouldNotifyDebuggerOfWaitCompletion && Task.AnyTaskRequiresNotifyDebuggerOfWaitCompletion(_tasks);
}
}
} }

首先我们来看看TaskFactory的ContinueWhenAny方法,ContinueWhenAny方法主要调用的是ContinueWhenAnyImpl,在ContinueWhenAnyImpl里面主要调用的是TaskFactory.CommonCWAnyLogic(tasks)方法,这个方法方返回的是一个CompleteOnInvokePromise Task,在Task的WhenAny方法中直接返回这个CompleteOnInvokePromise task,而Task的WaitAny则需要等待这个CompleteOnInvokePromise task的完成;而TaskFactory的ContinueWhenAny则是返回这个CompleteOnInvokePromise task的ContinueWith方法。

接下来我们在看看TaskFactory的ContinueWhenAll方法,ContinueWhenAll方法主要调用的是ContinueWhenAllImpl方法,ContinueWhenAllImpl方法主要是调用TaskFactory.CommonCWAnyLogic(tasks)方法,TaskFactory.CommonCWAnyLogic(tasks)方法返回一个CompleteOnCountdownPromise<T> 的task,然后ContinueWhenAllImpl最后返回这个task的ContinueWith方法,这里的CompleteOnCountdownPromise和Task的WhenAllPromise相似,里面都有一个计数器来标记里面的task是否执行完毕。

C# Task WhenAny和WhenAll 以及TaskFactory 的ContinueWhenAny和ContinueWhenAll的实现的更多相关文章

  1. 《C#并发编程经典实例》学习笔记—2.5 等待任意一个任务完成 Task.WhenAny

    问题 执行若干个任务,只需要对其中任意一个的完成进行响应.这主要用于:对一个操作进行多种独立的尝试,只要一个尝试完成,任务就算完成.例如,同时向多个 Web 服务询问股票价格,但是只关心第一个响应的. ...

  2. 【转】【C#】【Thread】【Task】多线程

    多线程 多线程在4.0中被简化了很多,仅仅只需要用到System.Threading.Tasks.::.Task类,下面就来详细介绍下Task类的使用. 一.简单使用 开启一个线程,执行循环方法,返回 ...

  3. 第四节:Task的启动的四种方式以及Task、TaskFactory的线程等待和线程延续的解决方案

    一. 背景 揭秘: 在前面的章节介绍过,Task出现之前,微软的多线程处理方式有:Thread→ThreadPool→委托的异步调用,虽然也可以基本业务需要的多线程场景,但它们在多个线程的等待处理方面 ...

  4. C# Task TaskFactory 异步线程/异步任务

    Task是.NetFramework3.0出现的,线程是基于线程池,然后提供了丰富的API TaskFactory  提供对创建和计划 Task 对象的支持 创建和启动异步任务 1.Task task ...

  5. c# Task waitAll,WhenAll

    wait 阻塞的 when是异步的非阻塞的. Task[] tlist = new Task[] { Task.Run(() => { Thread.Sleep(3000); }), Task. ...

  6. 实践基于Task的异步模式

    Await 返回该系列目录<基于Task的异步模式--全面介绍> 在API级别,实现没有阻塞的等待的方法是提供callback(回调函数).对于Tasks来说,这是通过像ContinueW ...

  7. 任务(task)

    任务概述 线程(Thread)是创建并发的底层工具,因此有一定的局限性(不易得到返回值(必须通过创建共享域):异常的捕获和处理也麻烦:同时线程执行完毕后无法再次开启该线程),这些局限性会降低性能同时影 ...

  8. Class:Task 类

    ylbtech-.Net-Class:Task 类 1. Task 类返回顶部 1-1. #region 程序集 mscorlib, Version=4.0.0.0, Culture=neutral, ...

  9. 多线程三:Task

    Task是.NET 3.0中推出的,是基于ThreadPool封装的,里面的线程都是来自于ThreadPool. 1.使用Run()方法启动线程 F12查看Run()方法的定义: 发现Run()方法的 ...

随机推荐

  1. net core体系-web应用程序-4net core2.0大白话带你入门-8asp.net core 内置DI容器(DependencyInjection,控制翻转)的一点小理解

    asp.net core 内置DI容器的一点小理解   DI容器本质上是一个工厂,负责提供向它请求的类型的实例. .net core内置了一个轻量级的DI容器,方便开发人员面向接口编程和依赖倒置(IO ...

  2. C#基础:委托之Action<T>和Func<T>的用法

  3. redis虚拟内存

    对于redis 这样的内存数据库, 内存总是不够用的. 除了可以将数据分割到多个 redis 服务器以外. 另外的能够提高数据库容量的办法就是使用虚拟内存技术把那些不经常访问的数据交换到磁盘上 如果我 ...

  4. 最小生成树-QS Network(Prim)

    题目大意: 给出的案例结果得出步骤,如下图所示,从结点1开始查找,找出的一条路径如绿色部分所标注.(关键处在于连接每条路径所需要的适配器的价格得加上去) 代码实现: #include<iostr ...

  5. BZOJ 4260 Codechef REBXOR (区间异或和最值) (01字典树+DP)

    <题目链接> 题目大意:给定一个序列,现在求出两段不相交的区间异或和的最大值. 解题分析: 区间异或问题首先想到01字典树.利用前缀.后缀建树,并且利用异或的性质,相同的两个数异或变成0, ...

  6. 开源医学图像处理平台NiftyNet介绍

    18年下半年10月份左右,老师分配有关NiftyNet平台的相关学习的任务,时隔5个月,决定整理一下以前的笔记,写成相应的博客! 目录 1.NiftyNet平台简介 2.NiftyNet平台架构设计 ...

  7. Misunderstood-Missing-逆向DP

    Misunderstood … Missing 记忆深刻......打铁没做出来的题 题意 : 打怪,有 A 的攻击力,有 D 的成长,初始均为 0,有 n 轮. 同时有三个数组 a[1:n],b[1 ...

  8. SpringMVC(二七) 自定义视图

    可以参考博客http://www.cnblogs.com/parryyang/p/5683600.html,举例很清晰. 对自定义的视图名称匹配不同的解析器进行解析. 作用:自己定义视图,视图继承vi ...

  9. word表分页表头

    选中表,右键-表格属性. 调出表格属性对话框. 选择行,在各页顶端以标题行形式重复出现划上钩确定.

  10. php数组和对象转换函数

    /**  * 数组 转 对象  *  * @param array $arr 数组  * @return object  */ function array_to_object($arr) {     ...