随笔,再聊异步函数机制

1,异步函数做了以下事情.

  • 创建一个状态机对象
  • 创建一个m_builder对象---一个TaskCompleteSource<TResult>对象,类似的.

  • 返回该对象的Task
  • 状态机在 await 操作符上面,做了以下几件事情
  1.                  调用GetAwaiter()函数来获取一个TaskAwaiter对象:
  2.                  如果其状态是Iscompleted,则进行进行GetResult获取异步函数结果,如果是没完成状态,则给其添加一个回调函数
  3.                  当异步任务完成后,引用该异步任务的ContinueWith来调用状态机的MoveNext()函数.
  4.                  在返回状态机的第一步,状态机调用GetResult函数来获取awaiter的结果.(如果异步函数出错的话,会报错.)
  5.                  当函数有错的时候,就设定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
原文地址:https://www.cnblogs.com/frogkiller/p/12527595.html