1. 程式人生 > >28.4 非同步函式的擴充套件性

28.4 非同步函式的擴充套件性

 

    class Program
    {
        static void Main()
        {
            Go();
            Console.ReadKey();
        }
        public static async Task Go()
        {
#if DEBUG
            //使用會影響效能和記憶體,所以只在除錯生成中啟用它
            TaskLogger.LogLevel = TaskLogger.TaskLogLevel.Pending;
#endif //初始化為3個任務:為測試TaskLogger,我們顯示控制其持續時間 var tasks = new List<Task> { Task.Delay(2000).Log("2s op"), Task.Delay(5000).Log("5s op"), Task.Delay(6000).Log("6s op") }; try {
//等待全部任務,但在 3秒後取消:只有一個任務能按時完成 await Task.WhenAll(tasks).WithCancellation(new CancellationTokenSource(3000).Token); } catch (Exception) { //查詢logger哪些任務尚未完成,按照從等待時間最長到最短的順序排序 foreach (var op in TaskLogger.GetLogEntries().OrderBy(tle => tle.LogTime)) Console.WriteLine(op); } } }
public static class TaskLogger { public enum TaskLogLevel { None, Pending } public static TaskLogLevel LogLevel { get; set; } private static readonly ConcurrentDictionary<Task, TaskLogEntry> s_log = new ConcurrentDictionary<Task, TaskLogEntry>(); public static IEnumerable<TaskLogEntry> GetLogEntries() { return s_log.Values; } 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 int 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); } } public static Task<TResult> Log<TResult>(this Task<TResult> task, string tag = null, [CallerMemberName] string callerMemberName = null, [CallerFilePath] string callerFilePath = null, [CallerLineNumber] int 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] int callerLineNumber = -1) { if (LogLevel == TaskLogLevel.None) return task; var logEntry = new TaskLogEntry { Task = task, LogTime = DateTime.Now, Tag = tag, CallerMemberName = callerMemberName, CallerFilePath = callerFilePath, CallerLineNumber = callerLineNumber }; s_log[task] = logEntry; task.ContinueWith(t => { TaskLogEntry entry; s_log.TryRemove(t, out entry); }, TaskContinuationOptions.ExecuteSynchronously); return task; } private struct Void { } //因為沒有非泛型的TaskCompletionSource類 public static async Task WithCancellation(this Task originalTask, CancellationToken token) { //建立在CancellationToken被取消時完成的一個Task var cancelTask = new TaskCompletionSource<Void>(); //一旦CancellationToken被取消就完成Task using (token.Register(t => ((TaskCompletionSource<Void>)t).TrySetResult(new Void()), cancelTask)) { //建立在原始Task或CancellationToken Task完成時都完成的一個Task Task any = await Task.WhenAny(originalTask, cancelTask.Task); if (any == cancelTask.Task) token.ThrowIfCancellationRequested(); } //等待原始任務(以同步方式):若任務失敗,等待它將丟擲第一個內部異常 而不是丟擲AggregateException await originalTask; } }

 

    class Program
    {
        static void Main()
        {
            Go();
        }
        public static void Go()
        {
            ShowExceptions();
            for (int i = 0; i < 3; i++)
            {
                try
                {
                    switch (i)
                    {
                        case 0: throw new InvalidOperationException();
                        case 1: throw new ObjectDisposedException("");
                        case 2: throw new ArgumentOutOfRangeException();
                    }
                }
                catch { }
            }
        }
        private static async void ShowExceptions()
        {
            var eventAwaiter = new EventAwaiter<FirstChanceExceptionEventArgs>();
            AppDomain.CurrentDomain.FirstChanceException += eventAwaiter.EventRaised;
            while (true)
                Console.WriteLine("AppDomain exception:{0}", (await eventAwaiter).Exception.GetType());
        }
    }
    public sealed class EventAwaiter<TEventArgs> : INotifyCompletion
    {
        private ConcurrentQueue<TEventArgs> m_events = new ConcurrentQueue<TEventArgs>();
        private Action m_continuation;

        //狀態機先呼叫這個來獲得awaiter 自己返回自己
        public EventAwaiter<TEventArgs> GetAwaiter() { return this; }
        //告訴狀態機是否發生了任何事件
        public bool IsCompleted { get { return m_events.Count > 0; } }
        //狀態機告訴我們以後要呼叫什麼方法  把它儲存起來
        public void OnCompleted(Action continuation)
        {
            Volatile.Write(ref m_continuation, continuation);
        }

        //狀態機查詢結果 這是await操作符的結果
        public TEventArgs GetResult()
        {
            TEventArgs e;
            m_events.TryDequeue(out e);
            return e;
        }

        //如果都引發了事件,多個執行緒可能同時呼叫
        public void EventRaised(object sender, TEventArgs eventArgs)
        {
            m_events.Enqueue(eventArgs);
            //如果有一個等待進行的延續任務,該執行緒會執行它
            Action continuation = Interlocked.Exchange(ref m_continuation, null);
            if (continuation != null) continuation();   //恢復狀態機
        }
    }