• 20181110_wait和async


    一. Awit和async的由来:

    await/async本身是一个语法糖,编译器提供的一个简化编程的功能; 在C#升级和.net Framework升级的时候, 产生的, 所以说并不是CLR的产物

    二. 用法:

    a)   Async出现在方法的声明上, 任何一个方法添加一个async关键字都不会报错

    b)   如果只有awit, 是会报错的

    c)   Awit必须放在task前面, 必须和async成对出现

    d)   Awit和async成对出现, 会被编译成状态机

    三. 一个简单的示例:

    private static async void NoReturn()
            {
                //主线程执行
                Console.WriteLine($"NoReturn Sleep before await,ThreadId={Thread.CurrentThread.ManagedThreadId}");
                TaskFactory taskFactory = new TaskFactory();
                //主线程启动一个子线程执行
                Task task = taskFactory.StartNew(() =>
                {
                    Console.WriteLine($"NoReturn Sleep before,ThreadId={Thread.CurrentThread.ManagedThreadId}");
                    Thread.Sleep(3000);
                    Console.WriteLine($"NoReturn Sleep after,ThreadId={Thread.CurrentThread.ManagedThreadId}");
                });
                await task;//主线程碰到await就返回去执行主线程的其它任务(循环), 而这个方法的下面的代码则不再执行, 等待主线程把其它任务执行完毕, 程序会再次跳回来执行这个方法的下面的其它代码; 但是注意, 再次跳回来的时候, 并不一定是主线程执行, 也有可能是新开一个线程来执行
                //这个回调的线程是不确定的:可能是主线程  可能是子线程  也可能是其他线程
                Console.WriteLine($"NoReturn Sleep after await,ThreadId={Thread.CurrentThread.ManagedThreadId}");
            }
    
    
    	//调用代码:
    
    
    		NoReturn();
                    for (int i = 0; i < 10; i++)
                    {
                        Thread.Sleep(300);
                        Console.WriteLine($"Main Thread Task ManagedThreadId={Thread.CurrentThread.ManagedThreadId} i={i}");
        
                    }

    四. Await和async的返回值

    a) 当使用await和async时, 如果没有返回值, 则应该标明使用Task作为返回值, 下面的代码演示没有返回值的await和async:

    private static async Task  NoReturnTask()
            {
                //这里还是主线程的id
                Console.WriteLine($"NoReturnTask Sleep before await,ThreadId={Thread.CurrentThread.ManagedThreadId}");
    
                Task task = Task.Run(() =>
                 {
                     Console.WriteLine($"NoReturnTask Sleep before,ThreadId={Thread.CurrentThread.ManagedThreadId}");
                     Thread.Sleep(3000);
                     Console.WriteLine($"NoReturnTask Sleep after,ThreadId={Thread.CurrentThread.ManagedThreadId}");
                 });
                await task;
                Console.WriteLine($"NoReturnTask Sleep after await,ThreadId={Thread.CurrentThread.ManagedThreadId}");
                 
            }

     b)  当使用await和async时, 如果有返回值, 则应该和Task组成泛型来返回: Task<typeName>, 下面的代码演示有返回值的await和async

    private static async Task<long> SumAsync()
            { 
                Console.WriteLine($"SumAsync 111 start ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
                long result = 0;
                //1. 先启动一个线程, 主线程遇到这里之后, 就会返回去了, 这个子线程开始执行
                await Task.Run(() =>
                { 
                    for (long i = 0; i < 999999999; i++)
                    {
                        result += i;
                    }
                }); 
                return result;
            }

    c)  Awati和async返回值的使用:

    Task<long> t = SumAsync();
                    Console.WriteLine($"Main Thread Task ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
                    long lResult = t.Result;//当需要访问result时, 则当前线程必须等待t线程的完成
                    t.Wait();//等价于上一行

    五.  利用await和async像写同步代码一样编写异步执行的代码, 调用方法和第四步的c相同:

    /// <summary>
            /// 带返回值的Task  
            /// 要使用返回值就一定要等子线程计算完毕
            /// </summary>
            /// <returns>async 就只返回long</returns>
            private static async Task<long> SumAsync()
            {
                //在await 和 async 中, 先启动一个线程, 执行完成之后, 接着可以继续awit
                //有点类似同步的方式编程, 但是却是异步执行
    
               
                Console.WriteLine($"SumAsync 111 start ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
                long result = 0;
                //1. 先启动一个线程, 主线程遇到这里之后, 就会返回去了, 这个子线程开始执行
                await Task.Run(() =>
                {
                    for (int k = 0; k < 10; k++)
                    {
                        Console.WriteLine($"SumAsync {k} await Task.Run ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
                        Thread.Sleep(1000);
                    }
    
                    for (long i = 0; i < 999999999; i++)
                    {
                        result += i;
                    }
                });
                //2. 上面的线程执行完成之后, 输出下面这句话; 可以看做这里是其它的动作
                Console.WriteLine($"SumFactory 111   end ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
    
                //3. 然后继续执行下面这里的线程, 这里又有一个await, 然后主线程又返回去执行其他的
                await Task.Run(() =>
                {
                    for (int k = 0; k < 10; k++)
                    {
                        Console.WriteLine($"SumAsync {k} await Task.Run ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
                        Thread.Sleep(1000);
                    }
    
                    for (long i = 0; i < 999999999; i++)
                    {
                        result += i;
                    }
                });
                //4. 这个线程执行完成之后, 开始执行这里输出
                Console.WriteLine($"SumFactory 111   end ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
    
                //5. 碰到await之后, 开了一个子线程, 然后又返回去了
                await Task.Run(() =>
                {
                    for (int k = 0; k < 10; k++)
                    {
                        Console.WriteLine($"SumAsync {k} await Task.Run ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
                        Thread.Sleep(1000);
                    }
    
                    for (long i = 0; i < 999999999; i++)
                    {
                        result += i;
                    }
                });
    
                Console.WriteLine($"SumFactory 111   end ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
                
                return result;
            } 

    六. 总结:

        // 1 使用async和await , 能够像写同步代码的方式一样, 达到异步执行的功能
    
          // 2 如果 awit / async 没有返回值, 则使用Task来替代(虽然允许写成void, 但是不要那样做);无返回值时  async Task == async void
    
          // 3 如果有返回值则使用Task<类型> 来处理
    
         // 4 await只能出现在Task前面
    
         // 5 不能单独await
    
         // 6 await 只能放在task前面
    
        // 7 不管你的await和async标识的方法需不需要返回值, 都不推荐void返回, 应该使用Task来代替, 像第二条所说那样, 因为返回Task和Task<T>则能够使用await, 并且可以和Task.WhenAny, Task.WhenAll等方式组合使用, 但是如果返回Void 不行, 则这条线程链就断了
    
        // 8 如果 awit / async 没有返回值, 则使用Task来替代, 如果有返回值则使用Task<类型>来处理
    

      

  • 相关阅读:
    异步请求与中断 ( XHR,Axios,Fetch对比 )
    界面组件Telerik UI for WPF入门指南 如何在运行时切换主题
    界面控件Telerik UI for WinForms入门指南 使用VS下载新版本
    Web界面开发框架DevExtreme v21.2 增强Data Grid功能
    DevExpress WPF入门指南 运行时生成的POCO视图模型(二)
    DevExpress WPF入门指南 运行时生成的POCO视图模型(三)
    B/S端界面控件DevExtreme ASP.NET MVC入门指南 模板语法(二)
    DevExpress跨平台产品——为.NET 7做好准备
    B/S端界面控件DevExtreme ASP.NET MVC入门指南 模板语法(三)
    UI组件Kendo UI for jQuery数据管理教程 TaskBoard/资源
  • 原文地址:https://www.cnblogs.com/wxylog/p/9940916.html
Copyright © 2020-2023  润新知