1,异步函数做了以下事情.
- 创建一个状态机对象
- 创建一个m_builder对象---一个TaskCompleteSource<TResult>对象,类似的.
- 返回该对象的Task
- 状态机在 await 操作符上面,做了以下几件事情
- 调用GetAwaiter()函数来获取一个TaskAwaiter对象:
- 如果其状态是Iscompleted,则进行进行GetResult获取异步函数结果,如果是没完成状态,则给其添加一个回调函数
- 当异步任务完成后,引用该异步任务的ContinueWith来调用状态机的MoveNext()函数.
- 在返回状态机的第一步,状态机调用GetResult函数来获取awaiter的结果.(如果异步函数出错的话,会报错.)
- 当函数有错的时候,就设定SetException(exception),没错的时候,就设定SetResult(result).
2,结论:
1,如果异步函数使用嵌套:那么 所有在await之前的代码都是同步完成的,task1-->task2--->task3...然后await后面的代码是异步完成的,但是对于task1,来说,是 task3---完成了---task2----完成了---task1---完成了.
2,异步函数终结一般来说是使用
public static async Task WithCancellation(this Task originalTask, CancellationToken ct) { var cancelTask = new TaskCompletionSource<Void>(); using (ct.Register( t => ((TaskCompletionSource<Void>)t).TrySetResult(new Void()), cancelTask)) { Task any = await Task.WhenAny(originalTask, cancelTask.Task); if (any == cancelTask.Task) ct.ThrowIfCancellationRequested(); } await originalTask; }
3,TaskLogger类
public static class TaskLogger { public enum TaskLogLevel { None, Pending } public static TaskLogLevel LogLevel { get; set; } public sealed class TaskLogEntry { public Task Task { get; internal set; } public String Tag { get; internal set; } public DateTime LogTime { get; internal set; } public String CallerMemberName { get; internal set; } public String CallerFilePath { get; internal set; } public Int32 CallerLineNumber { get; internal set; } public override string ToString() { return String.Format("LogTime={0},Tag={1},Member={2},File={3}({4}))", LogTime, Tag ?? "(None)", CallerMemberName, CallerFilePath, CallerLineNumber); } } private static readonly ConcurrentDictionary<Task, TaskLogEntry> s_log = new ConcurrentDictionary<Task, TaskLogEntry>(); public static IEnumerable<TaskLogEntry> GetLogEntries() { return s_log.Values; } public static Task<TResult> Log<TResult>(this Task<TResult> task, String tag = null, [CallerMemberName] String callerMemberName = null, [CallerFilePath] String callerFilePath = null, [CallerLineNumber] Int32 callerLineNumber = -1) { return (Task<TResult>) Log((Task)task, tag, callerMemberName, callerFilePath, callerLineNumber); } public static Task Log(this Task task, String tag = null, [CallerMemberName] String callerMemberName = null, [CallerFilePath] String callerFilePath = null, [CallerLineNumber] Int32 callerLineNumber = -1) { if (LogLevel == TaskLogLevel.None) return task; var logEntry = new TaskLogEntry { Task = task, LogTime = DateTime.Now, Tag = tag, CallerFilePath = callerFilePath, CallerLineNumber = callerLineNumber, CallerMemberName = callerMemberName }; s_log[task] = logEntry; task.ContinueWith(t => { TaskLogEntry entry; s_log.TryRemove(t, out entry); }, TaskContinuationOptions.ExecuteSynchronously); return task; } }
特别注意三个Caller特性,表明将获取Caller的属性.
public void DoProcessing() { TraceMessage("Something happened."); } public void TraceMessage(string message, [System.Runtime.CompilerServices.CallerMemberName] string memberName = "", [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "", [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0) { System.Diagnostics.Trace.WriteLine("message: " + message); System.Diagnostics.Trace.WriteLine("member name: " + memberName); System.Diagnostics.Trace.WriteLine("source file path: " + sourceFilePath); System.Diagnostics.Trace.WriteLine("source line number: " + sourceLineNumber); } // Sample Output: // message: Something happened. // member name: DoProcessing // source file path: c:UsersusernameDocumentsVisual Studio 2012ProjectsCallerInfoCSCallerInfoCSForm1.cs // source line number: 31