1:C#的三种异步的详细介绍及实现

本文涉及的产品
应用实时监控服务-应用监控,每月50GB免费额度
应用实时监控服务-用户体验监控,每月100OCU免费额度
简介: 一、介绍异步的前世今生:异步编程模型 (APM,Asynchronous Programming Model) 模式(也称 IAsyncResult 模式),在此模式中异步操作需要 Begin 和 End 方法(比如用于异步写入操作的 BeginWrite 和 EndWrite)。

一、介绍异步的前世今生:

  • 异步编程模型 (APM,Asynchronous Programming Model) 模式(也称 IAsyncResult 模式),在此模式中异步操作需要 Begin 和 End 方法(比如用于异步写入操作的 BeginWrite 和 EndWrite)。 对于新的开发工作不再建议采用此模式
  • 基于事件的异步模式 (EAP,Event-based Asynchronous Pattern),这种模式需要 Async 后缀,也需要一个或多个事件、事件处理程序委托类型和 EventArg 派生类型。 EAP 是在 .NET Framework 2.0 中引入的。 对于新的开发工作不再建议采用此模式。
  • 基于任务的异步模式 (TAP, Task-based Asynchronous Pattern) 使用一种方法来表示异步操作的启动和完成。 TAP 是在 .NET Framework 4 中引入的,并且它是在 .NET Framework 中进行异步编程的推荐使用方法。 C# 中的 async 和 await 关键词以及 Visual Basic 语言中的 Async 和 Await 运算符为 TAP 添加了语言支持。

 

二、我这里以一个Read方法为例,将异步操作简单进行讲解:

1.普通操作类
public class MyClass
{
    public int Read(byte [] buffer, int offset, int count);
}

 

2.异步编程模型(APM)
APM(Asynchronous Programming Model)是.Net 旧版本中广泛使用的异步编程模型。使用了 APM 的异步方法会返回一个 IAsyncResult 对象,这个对象有一个重要的属性 AsyncWaitHandle,他是一个 用来等待异步任务执行结束的一个同步信号。 如果不加 aResult.AsyncWaitHandle.WaitOne() 那么很有可能打印出空白,因为 BeginRead 只是“开始读取”。调用完成一般要调用 EndXXX 来回收资源。  APM 的特点是:方法名字以 BeginXXX 开头,返回类型为 IAsyncResult,调用结束后需要 EndXXX。  .Net 中有如下的常用类支持 APM:Stream、SqlCommand、Socket 等。  APM 还是太复杂,了解即可。 
public class MyClass
{
    public IAsyncResult BeginRead(
        byte [] buffer, int offset, int count,
        AsyncCallback callback, object state);
    public int EndRead(IAsyncResult asyncResult);
}

 

3.基于事件的异步模式(EAP)
类似于 Ajax 中的 XmlHttpRequest,send 之后并不是处理完成了,而是在 onreadystatechange 事件中再通知处理完成。

优点是简单,缺点是当实现复杂的业务的时候很麻烦,比如下载 A 成功后再下载 b,如果下载 b 成功再下载 c,否则就下载 d。

EAP 的类的特点是:一个异步方法配一个***Completed 事件。.Net 中基于 EAP 的类比较少。也有更 好的替代品,因此了解即可。

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

 

4.基于任务的异步模式(TAP)
public class MyClass
{
    public Task<int> ReadAsync(byte [] buffer, int offset, int count);
}

 

、我这里以一个下载资料方法为例,将异步操作简单进行讲解:

1.普通同步操作

private void btn_Click(object sender, EventArgs e)//这是同步按钮
        {
            using (WebClient wc = new WebClient())
            {
                // 我们尝试去下载 python 的安装包。
                wc.DownloadFile("https://file.aaoit.com/upload/AllLearnFile/admin//2018/4/24/c558f2dc9d6310bfe3cd1788094d3f0c.pdf", "C#课程第一单元学习.pdf");
            }
            label1.ForeColor = Color.Blue;
            label1.Text = "下载完成。";//提示的label
        }

2.基于事件的异步模式(EAP)

private void btnEAP_Click(object sender, EventArgs e)//这是EAP按钮
        {
            using (WebClient wc = new WebClient())
            {
                // 我们尝试去下载 python 的安装包。
                // 下载完成时会有事件通知。
                wc.DownloadFileCompleted += Wc_DownloadFileCompleted;
                wc.DownloadFileAsync(new Uri("https://file.aaoit.com/upload/AllLearnFile/admin//2018/4/24/c558f2dc9d6310bfe3cd1788094d3f0c.pdf"), "C#课程第一单元学习EAP.pdf");
            }
        }

        private void Wc_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
        {
            label1.ForeColor = Color.Yellow;
            label1.Text = "下载完成。";//提示的label
        }

 

3.异步编程模型(APM)

private void btnAPM_Click(object sender, EventArgs e)//这是APM按钮
        {
            FileStream fs = File.OpenRead("e:/cc.txt"); 
            byte[] buffer = new byte[16]; 
            IAsyncResult aResult = fs.BeginRead(buffer, 0, buffer.Length, null, null); 
            aResult.AsyncWaitHandle.WaitOne();//等待任务执行结束 
            MessageBox.Show(Encoding.UTF8.GetString(buffer));
            fs.EndRead(aResult); 
        }

 

4.基于任务的异步模式(TAP)

private async void btnTAP_Click(object sender, EventArgs e)//这是TAP按钮
        {
            using (WebClient wc = new WebClient())
            {
                // 我们尝试去下载 python 的安装包。
                Task task = wc.DownloadFileTaskAsync("https://file.aaoit.com/upload/AllLearnFile/admin//2018/4/24/c558f2dc9d6310bfe3cd1788094d3f0c.pdf", "C#课程第一单元学习TAP.pdf");
                // 可以在这里执行代码。
                await task;
            }
            label1.ForeColor = Color.Red;
            label1.Text = "下载完成。";//提示的label
        }

 

 

四、TPL(Task Parallel Library)是.Net 4.0 之后带来的新特性,更简洁,更方便。现在在.Net 平台下已经大面积使用。

TPL即任务并行库,是.NET Framework 4版本中的新鲜物,是System.Threading 和 System.Threading.Tasks 命名空间中的一组公共类型和 API。TPL 的目的在于简化向应用程序中添加并行性和并发性的过程,从而提高开发人员的工作效率。 TPL 会动态地按比例调节并发程度,以便最有效地使用所有可用的处理器。此外,TPL 还处理工作分区、ThreadPool 上的线程调度、取消支持、状态管理以及其他低级别的细节操作。通过使用 TPL,您可以在将精力集中于程序要完成的工作,同时最大程度地提高代码的性能。

1.实现读取txt

private async void btnTPL_Click(object sender, EventArgs e)//这是TPL按钮
        {
            FileStream fs = File.OpenRead("e:/cc.txt");
            byte[] buffer = new byte[16];
            int len = await fs.ReadAsync(buffer, 0, buffer.Length);
            MessageBox.Show("读取了" + len + "个字节");
            MessageBox.Show(Encoding.UTF8.GetString(buffer)); 
        }

注意方法中如果有 await,则方法必须标记为 async,不是所有方法都可以被轻松的标记 为 async。WinForm 中的事件处理方法都可以标记为 async、MVC 中的 Action 方法也可以标 记为 async、控制台的 Main 方法不能标记为 async。  TPL 的特点是:方法都以 XXXAsync 结尾,返回值类型是泛型的 Task<T>。  TPL 让我们可以用线性的方式去编写异步程序,不再需要像 EAP 中那样搞一堆回调、逻 辑跳来跳去了。await 现在已经被 JavaScript 借鉴走了!  用 await 实现“先下载 A,如果下载的内容长度大于 100 则下载 B,否则下载 C”就很容易了 。

2. WebClient 的 TPL 用法: 

 

private async void btnTPLWebClientNo_Click(object sender, EventArgs e)//这是TPLUI不卡死按钮
        {
            WebClient wc = new WebClient();
            string html = await wc.DownloadStringTaskAsync("https://www.aaoit.com");//不要丢了 await 
            MessageBox.Show(html); 
        }

        private void btnTPLWebClientYES_Click(object sender, EventArgs e)//这是TPLUI卡死按钮
        {
            WebClient wc = new WebClient();
            var task = wc.DownloadStringTaskAsync("https://www.aaoit.com"); 
            task.Wait(); 
            MessageBox.Show(task.Result); 
        }

WebClient、Stream、Socket 等这些“历史悠久”的类都同时提供了 APM、TPL 风格的 API,甚至有的还提供了 EAP 风格的 API。尽可能使用 TPL 风格的。 

 

相关实践学习
通过云拨测对指定服务器进行Ping/DNS监测
本实验将通过云拨测对指定服务器进行Ping/DNS监测,评估网站服务质量和用户体验。
目录
相关文章
|
7月前
|
编译器 数据处理 C#
C#中的异步流:使用IAsyncEnumerable<T>和await foreach实现异步数据迭代
【1月更文挑战第10天】本文介绍了C#中异步流的概念,并通过使用IAsyncEnumerable<T>接口和await foreach语句,详细阐述了如何异步地迭代数据流。异步流为处理大量数据或需要流式处理数据的场景提供了一种高效且非阻塞性的方法,使得开发者能够更优雅地处理并发和数据流问题。
|
18天前
|
C# UED SEO
C# 异步方法async / await任务超时处理
通过使用 `Task.WhenAny`和 `Task.Delay`方法,您可以在C#中有效地实现异步任务的超时处理机制。这种方法允许您在指定时间内等待任务完成,并在任务超时时采取适当的措施,如抛出异常或执行备用操作。希望本文提供的详细解释和代码示例能帮助您在实际项目中更好地处理异步任务超时问题,提升应用程序的可靠性和用户体验。
44 3
|
4月前
|
C#
C# async await 异步执行方法
C# async await 异步执行方法
54 0
|
6月前
|
C#
蓝易云 - C#将异步改成同步方法
注意:虽然这样可以将异步方法转为同步,但在实际开发中,我们通常推荐使用异步方法,因为它可以提高应用程序的响应性和并发性。将异步方法转为同步可能会导致死锁或性能问题。
48 2
|
7月前
|
C#
C#同步异步详解
C#同步异步详解
56 0
|
C# 开发者
C# 开发者技术:进程间数据共享之管道(Pipes)-异步通信版
主要类 1.NamedPipeClientStream 2.NamedPipeServerStream 解释:命名管道是一种进程间通信的方式,它允许不同进程之间在同一台机器上进行通信
947 2
C# 开发者技术:进程间数据共享之管道(Pipes)-异步通信版
|
C#
C#异步详解
c#异步编程原理,await asnyc的使用方法
62 0
|
存储 前端开发 API
C# 从做早餐看同步异步
C# 从做早餐看同步异步
57 0
|
存储 SQL 设计模式
C#异步有多少种实现方式?
C#异步有多少种实现方式?
c#异步多线程
c#异步多线程
80 0