zoukankan      html  css  js  c++  java
  • .NET中的并行处理,并发和异步编程。

      网上看了很多异步的方式,各种方式都有,梳理下.NET中编写异步的方式,避免混淆。.NET提供的异步方式可以归纳为三种:.NET中的并行处理,并发和异步编程。在梳理.NET中的并行处理,并发和异步编程之前,先来了解下同步、异步、并行、并发等概念

    一、异步编程中涉及的概念

      1、同步(Synchronous)和异步(Asynchronous)

        同步和异步的本质区别是是否需要等待,比如一个方法要执行,必须等前面一个方法程执行完成,才可以执行,这就是同步。如果不需要等上一个方法执行完成,并行或者并发执行,这就是异步调用。

      2、并发(Concurrency)和并行(Parallelism)

        并行才是真正意义上的并行执行,并发只是线程的交替执行,有可能存在串行的情况。在单核CPU的系统,线程只能是并发的,而不能支持并行,并行执行只能存在与多核CPU的系统。

        并行(parallel):指在同一时刻,有多条指令在多个处理器上同时执行。所以无论从微观还是从宏观来看,二者都是一起执行的。

        并发(concurrency):指在同一时刻只能有一条指令执行,但多个进程指令被快速的轮换执行,使得在宏观上具有多个进程同时执行的效果,但在微观上并不是同时执行的,只是把时间分成若干段,使多个进程快速交替的执行。

       3、临界区

        临界区,可以理解为公共的资源或者说共享数据。临界区具有保护性,也就是说,只能一个线程占用临界区,一旦一个线程占了临界区,另外一个线程是不予许再占用的,必须等线程释放了才行。

      4、阻塞(Blocking)和非阻塞(Non-Blocking)

        阻塞是线程的一种比较严重的情况,从前面我们知道了临界区只能允许一个线程占用,假如一个线程因为执行时间过长,占用了临界区,不挂起,其它想要占用临界区的线程只能等待,这种情况就容易造成线程阻塞。非阻塞的话就相反了,指所有线程都正常执行,不会出现线程占临界区不挂起的情况。

      5、饥饿(Starvation)、死锁(Deadlock)和活锁(Livelock)  

        饥饿,有些情况可能是一个线程优先级太低了,每次都被其它线程占用了,导致该线程一直不能占用临界区。也有一些情况是上一个线程执行时间太长了,一直没释放,导致其它线程都不能占用临界区,这也是造成线程饥饿。死锁有可能是因为线程死循环调用等等情况造成的,一旦出现这种情况估计就得人工排查了。活锁,是因为线程互相挂起临界区,给其它线程用,互相“谦让”,导致资源在两个或者几个线程之间跳到,这种情况就是活锁。

    二、异步编程  

      .NET提供了三种用于执行异步操作的模式:

    • 基于任务的异步模式(TAP),它使用一种方法来表示异步操作的启动和完成。TAP是在.NET Framework 4中引入的。这是.NET 中异步编程的推荐方法。C#中的asyncawait关键字以及Visual Basic中的AsyncAwait运算符添加了对TAP的语言支持。

    • 基于事件的异步模式(EAP),这是用于提供异步行为的基于事件的旧模型。它需要一种具有Async后缀和一个或多个事件,事件处理程序委托类型以及EventArg派生类型的方法。EAP是在.NET Framework 2.0中引入的。不再推荐用于新开发。

    • 异步编程模型(APM)模式(也称为IAsyncResult模式),这是使用IAsyncResult接口提供异步行为的旧模型。在这种模式下,同步操作需要BeginEnd方法(例如,BeginWriteEndWrite实现异步写操作)。对于新的开发,不再建议使用此模式。

      1、APM模式

      (1)APM详解

        APM是微软利用委托和线程池帮助我们实现的一个模式,该模式利用一个线程池线程去执行一个操作,在FileStream类BeginRead方法中就是执行一个读取文件操作,该线程池线程会立即将控制权返回给调用线程,此时线程池线程在后台进行这个异步操作;异步操作完成之后,通过回调函数来获取异步操作返回的结果。此时就是利用委托的机制。所以说APM是利用委托和线程池线程搞出来的模式,包括后面的基于事件的异步编程和基于任务的异步编程,还有C# 5中的async和await关键字,都是利用这委托和线程池搞出来的。他们的本质都一样,后面方法使异步编程更加简单。.NET1.0时期就提出的一种异步模式,并且基于IAsyncResult接口实现BeginXXX和EndXXX类似的方法。.net中有很多类实现了该模式(比如HttpWebRequest),同时我们也可以自定义类来实现APM模式(继承IAsyncResult接口并且实现BeginXXX和EndXXX方法)

      (2)HttpWebRequest示例

    using System;
    using System.IO;
    using System.Net;
    using System.Text;
    using System.Threading;
    
    namespace APMDemo
    {
        class Program
        {
            static void Main(string[] args)
            {
                string url = "https://www.baidu.com/";
                var request = HttpWebRequest.Create(url);
                request.BeginGetResponse(AsyncCallbackMethod, request);//BeginGetResponse,发起异步请求
                Console.WriteLine($"运行主线程");
                Console.ReadKey();
            }
    
            /// <summary>
            /// 回调方法
            /// </summary>
            /// <param name="asyncResult"></param>
            public static void AsyncCallbackMethod(IAsyncResult asyncResult)
            {
                HttpWebRequest request = asyncResult.AsyncState as HttpWebRequest;
                var response = request.EndGetResponse(asyncResult);//EndGetResponse异步请求完成
                var stream = response.GetResponseStream();
                StringBuilder sb = new StringBuilder();
                Console.WriteLine($"当前线程Id:{Thread.CurrentThread.ManagedThreadId}");
                using (StreamReader reader = new StreamReader(stream))
                {
                    var content = reader.ReadLine();
                    sb.AppendLine(content);
                    Console.WriteLine($"结果:{sb.ToString()}");
                }
            }
        }
    }
    View Code

      执行结果:

      

      2、EAP模式

      (1)详解

        EAP是.net 2.0提出的,实现了基于事件的异步模式的类将具有一个或者多个以Async为后缀的方法和对应的Completed事件,并且这些类都支持异步方法的取消、进度报告和报告结果。然而.net中并不是所有的类都支持EAP。当调用基于事件的EAP模式的类的XXXAsync方法时,就开始了一个异步操作,并且基于事件的EAP模式是基于APM模式之上的,而APM又是建立在委托之上的。下面的Demo就以BackgroundWorker类来演示如何使用EAP异步。

      (2)示例

    using System;
    using System.ComponentModel;
    
    namespace EAPDemo
    {
        class Program
        {
            static void Main(string[] args)
            {
                EAPManage.GetStudentAsync(4, student =>
                {
                    Console.WriteLine($"学生姓名:{student.Name}");
                });
                Console.WriteLine($"主线程中");
                Console.ReadKey();
            }
        }
    
        public class EAPManage
        {
            /// <summary>
            /// 获取信息
            /// </summary>
            /// <returns></returns>
            private static Student GetStudent(int stuID)
            {
                return new Student
                {
                    Id = stuID,
                    Name = "xiaoming"
                };
            }
    
            /// <summary>
            /// (async)
            /// </summary>
            /// <param name="userItem">contain: Guid(required)</param>
            /// <param name="handler">callback</param>
            public static void GetStudentAsync(int stuID, GetStudentHandler handler)
            {
                var background = new BackgroundWorker();
                background.DoWork += (sender, e) => { e.Result = GetStudent(stuID); };
                background.RunWorkerCompleted += (sender, e) =>
                {
                    if (handler == null || e.Result == null || e.Result.GetType() != typeof(Student)) return;
                    handler(e.Result as Student);
                };
                background.RunWorkerAsync();
            }
            public delegate void GetStudentHandler(Student student);
        }
    
        public class Student
        {
            public int Id { get; set; }
            public string Name { get; set; }
        }
    }
    View Code

      执行结果:

      

      3、TAP模式

      (1)详解

        .NET4.0提出了基于任务的异步编程模型,使用 Async 和 Await 的异步编程

    • 方法签名包含 async 修饰符,按照约定,异步方法的名称以“Async”后缀结尾
    • 方法通常包含至少一个 await 表达式,该表达式标记一个点,在该点上,直到等待的异步操作完成方法才能继续。 同时,将方法挂起,并且控制权返回到方法的调用方。
    • 异步方法在 await 表达式执行时暂停并不构成方法退出,只会导致 finally 代码块不运行
    • 标记的异步方法本身可以通过调用它的方法等待
    • 异步方法通常包含 await 运算符的一个或多个实例,但缺少 await 表达式也不会导致生成编译器错误。 如果异步方法未使用 await 运算符标记暂停点,那么异步方法即使有 async 修饰符也会作为同步方法执行,编译器将为此类方法发布一个警告

    三、并行编程

       并行开发目前还没有详细了解过,这里搜罗了比较好的文章,有时间研究下

      https://www.cnblogs.com/stoneniqiu/category/749413.html

      https://www.cnblogs.com/huangxincheng/category/368987.html

    四、线程

      之前写过一篇介绍线程的文章,这里就不在啰嗦了

  • 相关阅读:
    [linux]记录如何设置一个新的vps
    [python]使用virtualenvWrapper
    Vulkan Tutorial 07 Window surface
    Vulkan Tutorial 08 交换链
    Android实现小圆点显示未读功能
    【内附下载资料】第14次年度敏捷报告背后的趋势
    一文看懂人脸识别算法技术发展脉络
    实践案例丨基于ModelArts AI市场算法MobileNet_v2实现花卉分类
    美女面试官问我Python如何优雅的创建临时文件,我的回答....
    绝了,华为云服务器“The 3”出道,每款都很能打
  • 原文地址:https://www.cnblogs.com/qtiger/p/13495862.html
Copyright © 2011-2022 走看看