zoukankan      html  css  js  c++  java
  • C#异步编程のawait和async关键字来写异步程序

    一、await和async关键字

    .Net平台不断推出了新的异步编程模型,在.net4.5中加入了关键字await和async,顾名思义,await是指方法执行可等待,即可挂起直到有结果(不是必须立即占用主进程),async标明此方法是异步方法

    await 运算符在异步方法应用于任务,以挂起执行方法,直到所等待的任务完成。 任务表示正在进行的工作。

    在其中使用 await 的异步方法必须通过 async 关键字进行修改。 使用 async 修饰符定义并且通常包含一个或多个 await 表达式的这类方法称为异步方法。

    二、分析关键字结构及语法

         先解析一下专业名词:
         同步方法:一个程序调用某个方法,等到其执行完成之后才进行下一步操作。这也是默认的形式。
         异步方法:一个程序调用某个方法,在处理完成之前就返回该方法。通过 async/await 我们就可以实现这种类型的方法。
     
         async/await 结构可分成三部分:
         (1)调用方法:该方法调用异步方法,然后在异步方法执行其任务的时候继续执行;
         (2)异步方法:该方法异步执行工作,然后立刻返回到调用方法;
         (3)await 表达式:用于异步方法内部,指出需要异步执行的任务。一个异步方法可以包含多个 await 表达式(不存在 await 表达式的话 IDE 会发出警告)。
         异步方法:在执行完成前立即返回调用方法,在调用方法继续执行的过程中完成任务。
     
         语法分析:
         (1)关键字:方法头使用 async 修饰。
         (2)要求:包含 N(N>0) 个 await 表达式(不存在 await 表达式的话 IDE 会发出警告),表示需要异步执行的任务。
         (3)返回类型:只能返回 3 种类型(void、Task 和 Task<T>)。Task 和 Task<T> 标识返回的对象会在将来完成工作,表示调用方法和异步方法可以继续执行。
         (4)参数:数量不限,但不能使用 out 和 ref 关键字。
         (5)命名约定:方法后缀名应以 Async 结尾。
         (6)其它:匿名方法和 Lambda 表达式也可以作为异步对象;async 是一个上下文关键字;关键字 async 必须在返回类型前。

    三、异步调用http

            private async void startButton_Click(object sender, RoutedEventArgs e)
            {
                // Disable the button until the operation is complete.
                startButton.IsEnabled = false;
    
                resultsTextBox.Clear();
    
                // One-step async call.
                await SumPageSizesAsync();
    
                //// Two-step async call.
                //Task sumTask = SumPageSizesAsync();
                //await sumTask;
    
                resultsTextBox.Text += "
    Control returned to startButton_Click.
    ";
    
                // Reenable the button in case you want to run the operation again.
                startButton.IsEnabled = true;
            }
    
    
            private async Task SumPageSizesAsync()
            {
                // Declare an HttpClient object.
                HttpClient client = new HttpClient();
    
                // Make a list of web addresses.
                List<string> urlList = SetUpURLList();
    
                var total = 0;
    
                foreach (var url in urlList)
                {
                    // GetByteArrayAsync returns a task. At completion, the task
                    // produces a byte array.
                    byte[] urlContents = await client.GetByteArrayAsync(url);
    
                    // The following two lines can replace the previous assignment statement.
                    //Task<byte[]> getContentsTask = client.GetByteArrayAsync(url);
                    //byte[] urlContents = await getContentsTask;
                    DisplayResults(url, urlContents);
    
                    // Update the total.
                    total += urlContents.Length;
                }
    
                // Display the total count for all of the websites.
                resultsTextBox.Text +=
                    string.Format("
    
    Total bytes returned:  {0}
    ", total);
            }
    
    
            private List<string> SetUpURLList()
            {
                List<string> urls = new List<string> 
                { 
                    "http://msdn.microsoft.com/library/windows/apps/br211380.aspx",
                    "http://msdn.com",
                    "http://msdn.microsoft.com/en-us/library/hh290136.aspx",
                    "http://msdn.microsoft.com/en-us/library/ee256749.aspx",
                    "http://msdn.microsoft.com/en-us/library/hh290138.aspx",
                    "http://msdn.microsoft.com/en-us/library/hh290140.aspx",
                    "http://msdn.microsoft.com/en-us/library/dd470362.aspx",
                    "http://msdn.microsoft.com/en-us/library/aa578028.aspx",
                    "http://msdn.microsoft.com/en-us/library/ms404677.aspx",
                    "http://msdn.microsoft.com/en-us/library/ff730837.aspx"
                };
                return urls;
            }
    
    
            private void DisplayResults(string url, byte[] content)
            {
                // Display the length of each website. The string format 
                // is designed to be used with a monospaced font, such as
                // Lucida Console or Global Monospace.
                var bytes = content.Length;
                // Strip off the "http://".
                var displayURL = url.Replace("http://", "");
                resultsTextBox.Text += string.Format("
    {0,-58} {1,8}", displayURL, bytes);
            }

    四、其他示例

    public class MyClass  
    {  
        public MyClass()  
        {  
            DisplayValue(); //这里不会阻塞  
            System.Diagnostics.Debug.WriteLine("MyClass() End.");  
        }  
        public Task<double> GetValueAsync(double num1, double num2)  
        {  
            return Task.Run(() =>  
            {  
                for (int i = 0; i < 1000000; i++)  
                {  
                    num1 = num1 / num2;  
                }  
                return num1;  
            });  
        }  
        public async void DisplayValue()  
        {  
            double result = await GetValueAsync(1234.5, 1.01);//此处会开新线程处理GetValueAsync任务,然后方法马上返回  
            //这之后的所有代码都会被封装成委托,在GetValueAsync任务完成时调用  
            System.Diagnostics.Debug.WriteLine("Value is : " + result);  
        }  
    }  

    要执行异步操作的方法用async标记,调用方法时用await标记,被异步调用的方法返回值用<task>修饰。

    实际执行代码:

    public void DisplayValue()  
    {  
        System.Runtime.CompilerServices.TaskAwaiter<double> awaiter = GetValueAsync(1234.5, 1.01).GetAwaiter();  
        awaiter.OnCompleted(() =>  
            {  
                double result = awaiter.GetResult();  
                System.Diagnostics.Debug.WriteLine("Value is : " + result);  
            });  
    } 

    以下为某大神写的静态类,可以将一般方法转化为异步调用:

    public static class TaskAsyncHelper  
    02.{  
    03.    /// <summary>  
    04.    /// 将一个方法function异步运行,在执行完毕时执行回调callback  
    05.    /// </summary>  
    06.    /// <param name="function">异步方法,该方法没有参数,返回类型必须是void</param>  
    07.    /// <param name="callback">异步方法执行完毕时执行的回调方法,该方法没有参数,返回类型必须是void</param>  
    08.    public static async void RunAsync(Action function, Action callback)  
    09.    {  
    10.        Func<System.Threading.Tasks.Task> taskFunc = () =>  
    11.        {  
    12.            return System.Threading.Tasks.Task.Run(() =>  
    13.            {  
    14.                function();  
    15.            });  
    16.        };  
    17.        await taskFunc();  
    18.        if (callback != null)  
    19.            callback();  
    20.    }  
    21.  
    22.    /// <summary>  
    23.    /// 将一个方法function异步运行,在执行完毕时执行回调callback  
    24.    /// </summary>  
    25.    /// <typeparam name="TResult">异步方法的返回类型</typeparam>  
    26.    /// <param name="function">异步方法,该方法没有参数,返回类型必须是TResult</param>  
    27.    /// <param name="callback">异步方法执行完毕时执行的回调方法,该方法参数为TResult,返回类型必须是void</param>  
    28.    public static async void RunAsync<TResult>(Func<TResult> function, Action<TResult> callback)  
    29.    {  
    30.        Func<System.Threading.Tasks.Task<TResult>> taskFunc = ()=>  
    31.            {  
    32.                return System.Threading.Tasks.Task.Run(()=>  
    33.                    {  
    34.                        return function();  
    35.                    });  
    36.            };  
    37.        TResult rlt = await taskFunc();  
    38.        if(callback != null)  
    39.            callback(rlt);  
    40.    }  
    41.}  

    async用来修饰方法,表明这个方法是异步的,声明的方法的返回类型必须为:void,Task或Task<TResult>。

    await必须用来修饰Task或Task<TResult>,而且只能出现在已经用async关键字修饰的异步方法中。通常情况下,async/await成对出现才有意义,

    上面提到task.wait可以让主线程等待后台线程执行完毕,await和wait类似,同样是等待,等待Task<string>.Run()开始的后台线程执行完毕,不同的是await不会阻塞主线程

    欢迎加入qq群交流:568055323

  • 相关阅读:
    十二星座职业成功忠告
    一文为你详解Unique SQL原理和应用
    如何在软件发布计划中自动化语义化版本与变更日志
    云图说 | 云上资源管控有神器!关于IAM,你想知道的都在这里!
    15年华为云视频架构师采访实录:揭秘未来音视频行业的科技趋势!
    【智简联接,万物互联】华为云·云享专家董昕:Serverless和微服务下, IoT的变革蓄势待发
    让你的产品更懂世界:如何提升场景文本识别中的语言模型
    一文带你彻底了解大数据处理引擎Flink内存管理
    未雨绸缪,数据保护之NBU介质备份
    六个步骤,从零开始教你搭建基于WordPress的个人博客
  • 原文地址:https://www.cnblogs.com/xietianjiao/p/5969342.html
Copyright © 2011-2022 走看看