zoukankan      html  css  js  c++  java
  • 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();   //恢复状态机
            }
        }
  • 相关阅读:
    touch测试
    JS动画代码
    前端css、javascript在线工具
    横向广告(商品)滚动
    写点js的小函数(一)
    HTML5 css reset
    JS新API标准 地理定位(navigator.geolocation)
    写点js的小函数(二、文本框的提示)
    传说中的comet(ajax版)?
    lhgdialog 4.2.0 正式版发布
  • 原文地址:https://www.cnblogs.com/kikyoqiang/p/10204880.html
Copyright © 2011-2022 走看看