zoukankan      html  css  js  c++  java
  • asyns和await实现传统的异步---------C#

    刚开始,我认为async方法不好理解。现在我倒觉得很好理解,并且很好用。

    你不需要再用一个线程或者线程池去封装一个方法了。你只需要标明这个方法是async就可以了。

    传统的异步是利用回调函数来写的,写过的人都知道,,那样写的结构东一块西一块的,很不好找。

    所以在这里整理啦一下asyns和await实现的异步。。。

    asyns和await的异步刚开始学的时候不是很好理解。在这里,我在注释中,将细细的标明

     class Program
        {
            // ---------------规范说明-----------------------------
            //1.用async标识的方法即为异步方法,异步方法的返回值只能是void或者Task<object>或者Task。,---返回值是void的方法,不能使用await调用。注意你的返回类型。
            //2.在其他方法中调用异步方法时,可以加await,表示等待这个异步方法结束。 异步的关键点就在这个await
            //3.await标签只能写在异步方法中
            //4.await标识并调用的方法中,也必须要有await才行
            static void Main(string[] args)
            {
                //第一步,写了一个  “1”
                Console.WriteLine("1");
                
                Paint();
                //第三步----2,写了一个  “5”
                Console.WriteLine("5");
    
                Console.ReadLine();
            }
    
            //此方法是已经标明是异步方法
            async static void Paint()
            {
                //第二步,写了一个“2”
                Console.WriteLine("2");
    
                //第三步--1,代码发现await字段,整个方法将直接返回, 并在这个await这里加个标签,所以第三步输出的是“5”
                //等到 RequestBody方法返回值时,再次进入Paint方法中,并且直接从这个await字段处运行,
    
                //-----------------------------等待一秒---------这时候,已经输出了“5”
    
                //一秒后RequestBody方法返回值了,RequestBody的返回类型应该是Task<string>,
                //但是,用了await之后,返回值直接就是string
                //并且,输出“4”的操作被await阻塞
                Console.WriteLine(await RequestBody());
                Console.WriteLine("4");
       
            }
    
            async static Task<string> RequestBody()
            {    
                //被await调用的方法中,必须要有await
                return await Task.Run(() =>
                {
                    Thread.Sleep(2000);
                    return "3";
                });
            }
    
     
    
    
        }

     2016-1-11补充:其实上面的理解比较浅,关于异步函数的返回值有几种类型。是有错的。还有一种类型,是Task,就是本身

                 下面是我在书上看到的demo,是关于如何给异步函数限定运行时间的。超时之后,异步函数将被取消

    第一步,写一个类,里面放拓展方法

    public static class CancelTask
        {
            private struct Void { }
            public static async Task<TResult> WithCancellation<TResult>(this Task<TResult> originalTask, CancellationToken ct)
            {
                var cancellTask = new TaskCompletionSource<Void>();
                using (ct.Register(t => ((TaskCompletionSource<Void>)t).TrySetResult(new Void()), cancellTask))
                {
                    Task any = await Task.WhenAny(originalTask, cancellTask.Task);
                    if (any == cancellTask.Task)
                    {
                        ct.ThrowIfCancellationRequested();
                    }
                    return await originalTask;
                }
            }
    
            //这个方法不需要显示的写return
            public static async Task WithCancellation(this Task originalTask, CancellationToken ct)
            {
                var cancellTask = new TaskCompletionSource<Void>();
                using (ct.Register(t => ((TaskCompletionSource<Void>)t).TrySetResult(new Void()), cancellTask))
                {
                    Task any = await Task.WhenAny(originalTask, cancellTask.Task);
                    if (any == cancellTask.Task)
                    {
                        ct.ThrowIfCancellationRequested();
                    }
                  
                }
                await originalTask;
                //这里是可以无返回值的
            }
        }

    第二部,写一个log类。书上的log类写的好复杂。我看完瞎了眼。所以你只需要知道它是个log类,给你看运行效果的。软件发布时,不需要它

       public static class TaskLogger
        {
            public enum TaskLogLevel { None, Pending }
            public static TaskLogLevel LogLevel { get; set; }
            public sealed class TaskLogEntry
            {
                public Task Task { get; set; }
                public string Tag { get; set; }
                public DateTime LogTime { get; set; }
                public string CallerMemberName { get; set; }
                public string CallerFilePath { get; set; }
                public Int32 CallerLineNumber { get; 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,
                    CallerLineNumber = callerlinenumber,
                    CallerFilePath = callerfilepath,
                    CallerMemberName = callerMemberName
                };
                s_Log[task] = logEntry;
                task.ContinueWith(t => { TaskLogEntry entry; s_Log.TryRemove(t, out entry); }, TaskContinuationOptions.ExecuteSynchronously);
                return task;
            }


    第三部,写一个Go()方法

      class Program
        {
            static void Main(string[] args)
            {
                 Go();
                Console.ReadKey();
            }
    
            public static async Task Go()
            {
    #if DEBUG
                //使用TaskLogger会影响内存和性能,所以只在调试生成中使用它
                TaskLogger.LogLevel = TaskLogger.TaskLogLevel.Pending;
    #endif
                //初始化3个任务,为了测试TaskLogger,我们显示控制其持续时间
                var tasks = new List<Task>
                {
                    //delay的意思是延迟。意思是,如果这个task只用1秒钟就完成了操作。。这里可以延迟到两秒钟或者更久去结束它
                    Task.Delay(2000).Log("2s op"),
                      Task.Delay(5000).Log("5s op"),
                        Task.Delay(6000).Log("6s op"),
                };
                try
                {
                    //等待全部任务,但在3秒后取消;只有一个任务能按时完成
                    //注意:WithCancellation扩展方法的两个重载版本
                    await Task.WhenAll(tasks).WithCancellation(new CancellationTokenSource(3000).Token);
                    foreach (var op in TaskLogger.GetLogEntries().OrderBy(tle => tle.LogTime))
                    {
                        Console.WriteLine(op);
                    }
    
                }
                catch (OperationCanceledException)
                {
                    foreach (var op in TaskLogger.GetLogEntries().OrderBy(tle => tle.LogTime))
                    {
                        Console.WriteLine(op);
                    }
                }
            }
        }

    总结一下:关于async和await的关系。

    1.给方法前加async后,调用方法时,方法会异步执行,就像在一个线程里面执行一样。 但是,你要是用await调用async方法的话。,这个async方法就会同步执行。会阻塞它后面的操作。

    2.async方法可以用三种返回类型。

    Task<T>,这个可以返回一个有用的T类型,比如一个string

    Task,这些写的时候,方法不能显示的写return,方法会自动返回自身(是不是隐式的返回自身,这个我自己未验证。做到这一步,我是猜的。。你调试的时候,

              看下上面WithCancellation方法的返回值就可以知道我猜的对不对了)

    void,(这种返回类型我没写过,你自己看着研究)

  • 相关阅读:
    Hadoop Yarn 框架原理及运作机制及与MapReduce比较
    模型驱动与属性驱动区别
    spark伪分布式的安装
    大数据集群的常见问题
    linux常用命令
    大数据集群ssh登录其他机器失败 RSA host key for zb03 has changed and you have requested strict checking. Host key verification failed.
    Python 地点转化为经纬度
    Hbase原理、基本概念、基本架构
    struts2的java.lang.NoSuchMethodException错误
    抽象工厂
  • 原文地址:https://www.cnblogs.com/xiaoleye/p/4976446.html
Copyright © 2011-2022 走看看