个人感觉Task 的GetAwaiter和ConfigureAwait也是比较好理解的,首先看看他们的实现

public class Task<TResult> : Task
{
//Gets an awaiter used to await this
public new TaskAwaiter<TResult> GetAwaiter()
{
return new TaskAwaiter<TResult>(this);
} //Configures an awaiter used to await this
public new ConfiguredTaskAwaitable<TResult> ConfigureAwait(bool continueOnCapturedContext)
{
return new ConfiguredTaskAwaitable<TResult>(this, continueOnCapturedContext);
}
}

现在我们来看看TaskAwaiter<TResult>和ConfiguredTaskAwaitable<TResult>的实现:

public struct TaskAwaiter<TResult> : ICriticalNotifyCompletion
{
private readonly Task<TResult> m_task;
internal TaskAwaiter(Task<TResult> task)
{
Contract.Requires(task != null, "Constructing an awaiter requires a task to await.");
m_task = task;
} public bool IsCompleted
{
get { return m_task.IsCompleted; }
} public void OnCompleted(Action continuation)
{
TaskAwaiter.OnCompletedInternal(m_task, continuation, continueOnCapturedContext:true, flowExecutionContext:true);
} public void UnsafeOnCompleted(Action continuation)
{
TaskAwaiter.OnCompletedInternal(m_task, continuation, continueOnCapturedContext:true, flowExecutionContext:false);
} public TResult GetResult()
{
TaskAwaiter.ValidateEnd(m_task);
return m_task.ResultOnSuccess;
}
} public struct ConfiguredTaskAwaitable<TResult>
{
private readonly ConfiguredTaskAwaitable<TResult>.ConfiguredTaskAwaiter m_configuredTaskAwaiter;
internal ConfiguredTaskAwaitable(Task<TResult> task, bool continueOnCapturedContext)
{
m_configuredTaskAwaiter = new ConfiguredTaskAwaitable<TResult>.ConfiguredTaskAwaiter(task, continueOnCapturedContext);
} public ConfiguredTaskAwaitable<TResult>.ConfiguredTaskAwaiter GetAwaiter()
{
return m_configuredTaskAwaiter;
} [HostProtection(Synchronization = true, ExternalThreading = true)]
public struct ConfiguredTaskAwaiter : ICriticalNotifyCompletion
{
private readonly Task<TResult> m_task;
private readonly bool m_continueOnCapturedContext;
internal ConfiguredTaskAwaiter(Task<TResult> task, bool continueOnCapturedContext)
{
Contract.Requires(task != null, "Constructing an awaiter requires a task to await.");
m_task = task;
m_continueOnCapturedContext = continueOnCapturedContext;
} public bool IsCompleted
{
get { return m_task.IsCompleted; }
} public void OnCompleted(Action continuation)
{
TaskAwaiter.OnCompletedInternal(m_task, continuation, m_continueOnCapturedContext, flowExecutionContext:true);
} public void UnsafeOnCompleted(Action continuation)
{
TaskAwaiter.OnCompletedInternal(m_task, continuation, m_continueOnCapturedContext, flowExecutionContext:false);
} public TResult GetResult()
{
TaskAwaiter.ValidateEnd(m_task);
return m_task.ResultOnSuccess;
}
}
} public struct TaskAwaiter : ICriticalNotifyCompletion
{
private readonly Task m_task;
internal TaskAwaiter(Task task)
{
Contract.Requires(task != null, "Constructing an awaiter requires a task to await.");
m_task = task;
} public void OnCompleted(Action continuation)
{
OnCompletedInternal(m_task, continuation, continueOnCapturedContext:true, flowExecutionContext:true);
} public void UnsafeOnCompleted(Action continuation)
{
OnCompletedInternal(m_task, continuation, continueOnCapturedContext:true, flowExecutionContext:false);
} internal static void OnCompletedInternal(Task task, Action continuation, bool continueOnCapturedContext, bool flowExecutionContext)
{
if (continuation == null) throw new ArgumentNullException("continuation");
StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; // If TaskWait* ETW events are enabled, trace a beginning event for this await
// and set up an ending event to be traced when the asynchronous await completes.
if ( TplEtwProvider.Log.IsEnabled() || Task.s_asyncDebuggingEnabled)
{
continuation = OutputWaitEtwEvents(task, continuation);
} // Set the continuation onto the awaited task.
task.SetContinuationForAwait(continuation, continueOnCapturedContext, flowExecutionContext, ref stackMark);
} public void GetResult()
{
ValidateEnd(m_task);
} internal static void ValidateEnd(Task task)
{
if (task.IsWaitNotificationEnabledOrNotRanToCompletion)
{
HandleNonSuccessAndDebuggerNotification(task);
}
} /// Ensures the task is completed, triggers any necessary debugger breakpoints for completing
/// the await on the task, and throws an exception if the task did not complete successfully.
private static void HandleNonSuccessAndDebuggerNotification(Task task)
{
if (!task.IsCompleted)
{
bool taskCompleted = task.InternalWait(Timeout.Infinite, default(CancellationToken));
Contract.Assert(taskCompleted, "With an infinite timeout, the task should have always completed.");
} // Now that we're done, alert the debugger if so requested
task.NotifyDebuggerOfWaitCompletionIfNecessary(); // And throw an exception if the task is faulted or canceled.
if (!task.IsRanToCompletion) ThrowForNonSuccess(task);
}
}

TaskAwaiter<TResult>中的OnCompleted和UnsafeOnCompleted方法 参数continueOnCapturedContext为true,GetResult主要是调用TaskAwaiter.ValidateEnd(m_task)方法,而ConfiguredTaskAwaiter的OnCompleted和UnsafeOnCompleted方法中的m_continueOnCapturedContext参数不一定是true,是外面调用task的ConfigureAwait的参数continueOnCapturedContext,ConfiguredTaskAwaiter的GetResult也是调用TaskAwaiter.ValidateEnd(m_task)方法。那么让我们来看看TaskAwaiter的ValidateEnd方法,同时TaskAwaiter的GetResult方法也是调用自己的ValidateEnd,ValidateEnd方法主要是调用HandleNonSuccessAndDebuggerNotification方法,在HandleNonSuccessAndDebuggerNotification方法中检查task是否完成,没有完成我们就调用 task.InternalWait(Timeout.Infinite, default(CancellationToken))来阻塞task直到完成。

Task的ConfigureAwait中参数continueOnCapturedContext最后传递到了TaskAwaiter的OnCompletedInternal方法,也就是说你在调用Awaiter 的OnCompleted和UnsafeOnCompleted方法才有区别,一般调用GetResult是没有区别的。,OnCompletedInternal方法主要是调用task.SetContinuationForAwait(continuation, continueOnCapturedContext, flowExecutionContext, ref stackMark);方法,task的SetContinuationForAwait实现如下:

public class Task : IThreadPoolWorkItem, IAsyncResult, IDisposable
{
internal void SetContinuationForAwait(Action continuationAction, bool continueOnCapturedContext, bool flowExecutionContext, ref StackCrawlMark stackMark)
{
Contract.Requires(continuationAction != null);
TaskContinuation tc = null; // If the user wants the continuation to run on the current "context" if there is one...
if (continueOnCapturedContext)
{
var syncCtx = SynchronizationContext.CurrentNoFlow;
if (syncCtx != null && syncCtx.GetType() != typeof(SynchronizationContext))
{
tc = new SynchronizationContextAwaitTaskContinuation(syncCtx, continuationAction, flowExecutionContext, ref stackMark);
}
else
{
var scheduler = TaskScheduler.InternalCurrent;
if (scheduler != null && scheduler != TaskScheduler.Default)
{
tc = new TaskSchedulerAwaitTaskContinuation(scheduler, continuationAction, flowExecutionContext, ref stackMark);
}
}
} if (tc == null && flowExecutionContext)
{
tc = new AwaitTaskContinuation(continuationAction, flowExecutionContext: true, stackMark: ref stackMark);
} if (tc != null)
{
if (!AddTaskContinuation(tc, addBeforeOthers: false))
tc.Run(this, bCanInlineContinuationTask: false);
}
else
{
Contract.Assert(!flowExecutionContext, "We already determined we're not required to flow context.");
if (!AddTaskContinuation(continuationAction, addBeforeOthers: false))
AwaitTaskContinuation.UnsafeScheduleAction(continuationAction, this);
}
}
}

Task的SetContinuationForAwait方法里面涉及到SynchronizationContextAwaitTaskContinuation,TaskSchedulerAwaitTaskContinuation和AwaitTaskContinuation类,他们的主要方法如下,这里我也没有去调试,:

   /// Task continuation for awaiting with a current synchronization context.
internal sealed class SynchronizationContextAwaitTaskContinuation : AwaitTaskContinuation
{
private readonly static SendOrPostCallback s_postCallback = state => ((Action)state)(); // can't use InvokeAction as it's SecurityCritical
private static ContextCallback s_postActionCallback;
private readonly SynchronizationContext m_syncContext; internal SynchronizationContextAwaitTaskContinuation(SynchronizationContext context, Action action, bool flowExecutionContext, ref StackCrawlMark stackMark) :base(action, flowExecutionContext, ref stackMark)
{
Contract.Assert(context != null);
m_syncContext = context;
} internal sealed override void Run(Task task, bool canInlineContinuationTask)
{
if (canInlineContinuationTask && m_syncContext == SynchronizationContext.CurrentNoFlow)
{
RunCallback(GetInvokeActionCallback(), m_action, ref Task.t_currentTask);
}
else
{
TplEtwProvider etwLog = TplEtwProvider.Log;
if (etwLog.IsEnabled())
{
m_continuationId = Task.NewId();
etwLog.AwaitTaskContinuationScheduled((task.ExecutingTaskScheduler ?? TaskScheduler.Default).Id, task.Id, m_continuationId);
}
RunCallback(GetPostActionCallback(), this, ref Task.t_currentTask);
}
} private static void PostAction(object state)
{
var c = (SynchronizationContextAwaitTaskContinuation)state; TplEtwProvider etwLog = TplEtwProvider.Log;
if (etwLog.TasksSetActivityIds && c.m_continuationId != )
{
c.m_syncContext.Post(s_postCallback, GetActionLogDelegate(c.m_continuationId, c.m_action));
}
else
{
c.m_syncContext.Post(s_postCallback, c.m_action); // s_postCallback is manually cached, as the compiler won't in a SecurityCritical method
}
} private static ContextCallback GetPostActionCallback()
{
ContextCallback callback = s_postActionCallback;
if (callback == null) { s_postActionCallback = callback = PostAction; } // lazily initialize SecurityCritical delegate
return callback;
}
} internal sealed class TaskSchedulerAwaitTaskContinuation : AwaitTaskContinuation
{
private readonly TaskScheduler m_scheduler; internal TaskSchedulerAwaitTaskContinuation(TaskScheduler scheduler, Action action, bool flowExecutionContext, ref StackCrawlMark stackMark) : base(action, flowExecutionContext, ref stackMark)
{
Contract.Assert(scheduler != null);
m_scheduler = scheduler;
} internal sealed override void Run(Task ignored, bool canInlineContinuationTask)
{
// If we're targeting the default scheduler, we can use the faster path provided by the base class.
if (m_scheduler == TaskScheduler.Default)
{
base.Run(ignored, canInlineContinuationTask);
}
else
{ bool inlineIfPossible = canInlineContinuationTask &&
(TaskScheduler.InternalCurrent == m_scheduler || Thread.CurrentThread.IsThreadPoolThread); var task = CreateTask(state => {
try { ((Action)state)(); }
catch (Exception exc) { ThrowAsyncIfNecessary(exc); }
}, m_action, m_scheduler); if (inlineIfPossible)
{
InlineIfPossibleOrElseQueue(task, needsProtection: false);
}
else
{
try { task.ScheduleAndStart(needsProtection: false); }
catch (TaskSchedulerException) { } // No further action is necessary, as ScheduleAndStart already transitioned task to faulted
}
}
}
}
internal class AwaitTaskContinuation : TaskContinuation, IThreadPoolWorkItem
{
private readonly ExecutionContext m_capturedContext;
protected readonly Action m_action;
protected int m_continuationId; internal AwaitTaskContinuation(Action action, bool flowExecutionContext, ref StackCrawlMark stackMark)
{
Contract.Requires(action != null);
m_action = action;
if (flowExecutionContext)
{
m_capturedContext = ExecutionContext.Capture(ref stackMark, ExecutionContext.CaptureOptions.IgnoreSyncCtx | ExecutionContext.CaptureOptions.OptimizeDefaultCase);
}
} internal AwaitTaskContinuation(Action action, bool flowExecutionContext)
{
Contract.Requires(action != null);
m_action = action;
if (flowExecutionContext)
{
m_capturedContext = ExecutionContext.FastCapture();
}
} protected Task CreateTask(Action<object> action, object state, TaskScheduler scheduler)
{
Contract.Requires(action != null);
Contract.Requires(scheduler != null); return new Task( action, state, null, default(CancellationToken), TaskCreationOptions.None, InternalTaskOptions.QueuedByRuntime, scheduler)
{
CapturedContext = m_capturedContext
};
} internal override void Run(Task task, bool canInlineContinuationTask)
{ if (canInlineContinuationTask && IsValidLocationForInlining)
{
RunCallback(GetInvokeActionCallback(), m_action, ref Task.t_currentTask); // any exceptions from m_action will be handled by s_callbackRunAction
}
else
{
TplEtwProvider etwLog = TplEtwProvider.Log;
if (etwLog.IsEnabled())
{
m_continuationId = Task.NewId();
etwLog.AwaitTaskContinuationScheduled((task.ExecutingTaskScheduler ?? TaskScheduler.Default).Id, task.Id, m_continuationId);
}
ThreadPool.UnsafeQueueCustomWorkItem(this, forceGlobal: false);
}
} [SecurityCritical]
void ExecuteWorkItemHelper()
{
var etwLog = TplEtwProvider.Log;
Guid savedActivityId = Guid.Empty;
if (etwLog.TasksSetActivityIds && m_continuationId != )
{
Guid activityId = TplEtwProvider.CreateGuidForTaskID(m_continuationId);
System.Diagnostics.Tracing.EventSource.SetCurrentThreadActivityId(activityId, out savedActivityId);
}
try
{
if (m_capturedContext == null)
{
m_action();
}
else
{
try
{
ExecutionContext.Run(m_capturedContext, GetInvokeActionCallback(), m_action, true);
}
finally { m_capturedContext.Dispose(); }
}
}
finally
{
if (etwLog.TasksSetActivityIds && m_continuationId != )
{
System.Diagnostics.Tracing.EventSource.SetCurrentThreadActivityId(savedActivityId);
}
}
}
void IThreadPoolWorkItem.ExecuteWorkItem()
{
// inline the fast path
if (m_capturedContext == null && !TplEtwProvider.Log.IsEnabled())
{
m_action();
}
else
{
ExecuteWorkItemHelper();
}
} private static ContextCallback s_invokeActionCallback; private static void InvokeAction(object state) { ((Action)state)(); } protected static ContextCallback GetInvokeActionCallback()
{
ContextCallback callback = s_invokeActionCallback;
if (callback == null) { s_invokeActionCallback = callback = InvokeAction; } // lazily initialize SecurityCritical delegate
return callback;
} protected void RunCallback(ContextCallback callback, object state, ref Task currentTask)
{
Contract.Requires(callback != null);
Contract.Assert(currentTask == Task.t_currentTask); var prevCurrentTask = currentTask;
try
{
if (prevCurrentTask != null) currentTask = null;
if (m_capturedContext == null) callback(state);
else ExecutionContext.Run(m_capturedContext, callback, state, true);
}
catch (Exception exc) // we explicitly do not request handling of dangerous exceptions like AVs
{
ThrowAsyncIfNecessary(exc);
}
finally
{
if (prevCurrentTask != null) currentTask = prevCurrentTask;
if (m_capturedContext != null) m_capturedContext.Dispose();
}
} }

我在调试的时候,SetContinuationForAwait方法中的TaskContinuation是AwaitTaskContinuation实例,在AwaitTaskContinuation构造方法中【  m_capturedContext = ExecutionContext.FastCapture();】来捕获上下文。最后在Task的SetContinuationForAwait调用AwaitTaskContinuation的Run方法【tc.Run(this, bCanInlineContinuationTask: false)】,AwaitTaskContinuation的Run实现非常简单, 调用  ThreadPool.UnsafeQueueCustomWorkItem(this, forceGlobal: false);,实际就是调用AwaitTaskContinuation的ExecuteWorkItem方法,检查上下文m_capturedContext是否存在,存在调用ExecuteWorkItemHelper,ExecuteWorkItemHelper里面再调用  ExecutionContext.Run(m_capturedContext, GetInvokeActionCallback(), m_action, true); AwaitTaskContinuation是不是比较简单。SynchronizationContextAwaitTaskContinuation和TaskSchedulerAwaitTaskContinuation的Run方法就忽略吧,更简单。

C# Task的GetAwaiter和ConfigureAwait的更多相关文章

  1. 任务(task)

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

  2. C#中 Thread,Task,Async/Await 异步编程

    什么是异步 同步和异步主要用于修饰方法.当一个方法被调用时,调用者需要等待该方法执行完毕并返回才能继续执行,我们称这个方法是同步方法:当一个方法被调用时立即返回,并获取一个线程执行该方法内部的业务,调 ...

  3. 15.5.3 【Task实现细节】状态机的结构

    状态机的整体结构非常简单.它总是使用显式接口实现,以实现.NET 4.5引入的 IAsync StateMachine 接口,并且只包含该接口声明的两个方法,即 MoveNext 和 SetState ...

  4. 15.5.2 【Task实现细节】骨架方法的结构

    尽管骨架方法中的代码非常简单,但它暗示了状态机的职责.代码清单15-11生成的骨架方 法如下所示: [DebuggerStepThrough] [AsyncStateMachine(typeof(De ...

  5. 15.3 Task 语法和语义

    15.3.1 声明异步方法和返回类型 async static void GetStringAsync() { using (var client = new HttpClient()) { Task ...

  6. C# 使用Task执行异步操作

    为什么要使用 Task Task 和 Thread 区别 Task 介绍 Task 简单实现 Task 执行状态 为什么要使用 Task 线程是创建并发的底层工具,因此具有一定的局限性. 没有简单的方 ...

  7. C# Task.WhenAll

    1.有时候我们需要同时执行一些操作,然后把这些操作的结果进行汇总,以达到用异步处理降低操作耗时的效果,此时我们会考虑使用Task,而Task.WhenAll则排上了用场. public void Is ...

  8. C#关于在返回值为Task方法中使用Thread.Sleep引发的思考

    起因 最近有个小伙伴提出了一个问题,就是在使用.net core的BackgroundService的时候,对应的ExecuteAsync方法里面写如下代码,会使程序一直卡在当前方法,不会继续执行,代 ...

  9. 深入探究 WinRT 和 await

    在最近发布的使用 Windows 运行时中异步性来始终保持应用程序能够快速流畅地运行这篇博文中,包含了一些如何在 C# 和 Visual Basic 中使用 await 关键字的示例,允许开发人员在使 ...

随机推荐

  1. mariadb-半同步复制

    半同步复制: 使用插件 对于从节点,有一部分为同步复制,当主节点复制完从节点后才向客户返回ok,同步超时后自动降级为异步 有一部分为异步复制 这样为了与主节点冗余 基于主从的模式上搭建 半同步复制: ...

  2. 使用element-ui的常见问题

    给组件绑定的事件为什么无法触发?  在 Vue 2.0 中,为自定义组件绑定原生事件必须使用 .native 修饰符: <my-component @click.native="han ...

  3. day46 html

    老师的笔记: day46 课程安排 HTML CSS JS基础 DOM操作 jQuery Bootstrap pymysql Django基础 项目实战 Vue.js 今日概要: "PUT ...

  4. Spring(二)IOC底层实现原理

    IOC原理 将对象创建交给Spring去管理. 实现IOC的两种方式 IOC配置文件的方式 IOC注解的方式 IOC底层实现原理 底层实现使用的技术 1.1 xml配置文件 1.2 dom4j解析xm ...

  5. laravel启动过程简单解析

    :first-child{margin-top:0!important}img.plugin{box-shadow:0 1px 3px rgba(0,0,0,.1);border-radius:3px ...

  6. log4j和logback会互相冲突

    当两个都存在同一个项目的时候,本来应该走log4j的日志可能会走logback,导致日志级别问题等错误. 如果出现日志级别不受配置文件控制,可根据源代码走,找到原因.

  7. Mybatis if test 中int integer判断非空的坑

    Mybatis 中,alarmType 是int类型.如果alarmType 为0的话,条件判断返回结果为false,其它值的话,返回true. 1 <if test="alarmTy ...

  8. hdu2473

    hdu2473并查集的删除操作建立虚点,删除它就断掉了它在原图中的所有关系,而成为独立节点,而且它只能被删除一次,而且删除之后还能进行操作,采用映射(虚点)的方法,建立虚点并把删除之后的操作挪到虚点上 ...

  9. Misunderstood-Missing-逆向DP

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

  10. redsi搭建主从和多主多从