zoukankan      html  css  js  c++  java
  • c# 异步编程

    1. 引入

      同步,任务以固定的顺序执行。异步,任务不需要按照固定顺序执行。从.net4.5开始,异步主要通过Task实现。异步编程的核心是Task和Task<T>对象,用来模拟异步操作,并通过async和await关键字修饰。其中异步模型的操作,一般分为以下2种:

      (1)对于I/O绑定的代码,await将在异步方法中返回一个Task或Task<T>;

      (2)对于绑定CPU类的程序,await将在带有Task.Run()方法的后台线程上启动操作;

    2. 异步编程的三种模式

    • 基于任务的异步模式(TAP):TAP在.NET4.0中引入,使用单个犯法来表示异步操作的启动和完成,.NET中推荐使用该方法实现异步编程。 
    • 基于事件的异步模式(EAP):EAP在.NET Framework2.0中引入,用于提供异步行为的基于事件的遗留模型,需要一个async后缀的一个或多个时间,时间处理程序委托Type和EventArg-derived类型的方法。
    • 异步编程模型(APM):APM模型也称为AsyncResult模式,是使用IAsyncResult接口提供异步行为的传统模型。该模式中,异步操作需要begin()和end()方法,目前不推荐开发中使用该方法。

      这三种模式的实现,以"从指定的偏移量开始将指定数量的数据读入提供的缓存区"为例进行实现。

       public class MyClass
        {
            public int Read(byte[] buffer, int offset, int count);
        }

      该方法的TAP模式实现如下:

        public class MyClass
        {
           public Task<int> ReadAsync(byte[] buffer, int offset, int count);
        }

      EAP对应方法将公开一下类型和成员:

    public class MyClass  
    {  
        public void ReadAsync(byte [] buffer, int offset, int count);  
        public event ReadCompletedEventHandler ReadCompleted;  
    }  

      APM模式下实现如下:

    public class MyClass  
    {  
        public IAsyncResult BeginRead(byte [] buffer,int offset, int count,AsyncCallback callback, object state);  
        public int EndRead(IAsyncResult asyncResult);  
    }  

    3. 异步操作的实现

    3.1 I/O绑定实例  

      场景描述: 点击按钮从web服务下载数据,但不能锁定UI线程。

    private readonly HttpClient _httpClient=new HttpClient();
    downloadButton.Click +=async (o,e)=>
    {
           //在web服务请求发生时间向UI提供控制
           //UI线程自由地执行其他工作
           var stringData = await _httpClient.GetStringAsync(URL);
           DoSomethingWithData(stringData);
     }

    3.2 CPU绑定实例:执行游戏计算

      场景描述:写一个手机端游戏,点击按钮对屏幕上许多敌人造成伤害,但执行损害计算的代价可能是昂贵的,并且在UI线程上执行计算时可能导致界面暂停。

      解决该问题的最佳办法是开启一个用Task.Run工作的后台线程,用await等待返回结果。

    private DamageResult CalculateDamageDone()
    {
        // Code omitted:
        //
        // Does an expensive calculation and returns
        // the result of that calculation.
    }
    
    calculateButton.Clicked += async (o, e) =>
    {
        // This line will yield control to the UI while CalculateDamageDone()
        // performs its work.  The UI thread is free to perform other work.
        var damageResult = await Task.Run(() => CalculateDamageDone());
        DisplayDamage(damageResult);
    };

    3.3 关键点

    • 异步操作既可用于I/O绑定代码,也可用于CPU绑定代码;
    • 异步代码使用Task<T>和task,task用于在后台工作模式的构造;
    • async关键字标记方法为异步方法,允许在方法体中使用await关键字;
    • 当使用await关键字时,会暂停调用方法,并将控制权返回给它的调用方,知道等待的任务完成;
    • await只能被应用在async修饰的方法内

    3.4 如何分辨是I/O绑定还是CPU绑定?

      (1)如果代码需要“等待”,例如来自数据库的数据,则为I/O绑定;

      (2)如果代码执行需要消耗大代价的计算,则为CPU绑定。  

    4. 总结

    • async void只用于事件处理程序;async void方法中抛出的异常不能在该方法之外捕获;async void方法很难测试;async void如果调用者不希望是异步的,方法可能会有错误。
    • LINQ中的lambda表达式延迟执行,如果书写错误,可能很容易引起死锁。
  • 相关阅读:
    【转载】内存工作原理三
    【转载】内存工作原理二
    【转载】内存工作原理一
    【转载】ITU-RBT.656视频标准接口
    【转载】about slack
    【转载】VGA时序与原理
    Sed 命令详解 正则表达式元字符
    视频基础知识---分辨率
    DC基本知识问答
    vcs和verdi的联合仿真
  • 原文地址:https://www.cnblogs.com/mo-lu/p/11114671.html
Copyright © 2011-2022 走看看