当前位置: 首页 > news >正文

[.net 面向对象程序设计进阶] (19) 异步(Asynchronous) 使用异步创建快速响应和可伸缩性的应用程序...

[.net 面向对象程序设计进阶] (19) 异步(Asynchronous) 使用异步创建快速响应和可伸缩性的应用程序

本节导读:

本节主要说明使用异步进行程序设计的优缺点及如何通过异步编程.

使用传统方法BeginInvoke / EndInvoke来实现异步。

使用async/await 创建异步方法和事件。

通过异步编程创建具有快速响应和可伸缩性的应用程序。 

读前必备:

A.委托 [.net 面向对象编程基础]  (21) 委托

B.事件 [.net 面向对象编程基础] (22) 事件

1.异步程序设计的优缺点:

A.让用户界面快速响应;对于耗时操作阻塞UI线程,通过异步回调可使用UI快速响应。

B.创建高伸缩性的应用。对于服务端应用,创建更多线程来处理消耗资源较多,使用异步可使用主线程继续工作,不需要等待返回。使用程序具有更好的伸缩性。

对于异步的缺点,最主要一点就是比创建同步程序难度大一些,首先使用传统的方法创建异步,比起同步更容易出错。不过随着.NET的不断发展和第三方异步组件的丰富,创建异步应用程序也变得越来越简单了。

2.异步的实现

对于.NET中的异步编程,.NET在各个方向都几乎提供了同步和异步的两个方式来实现,在这里我们不能把.NET中全部的异步编程方法都列举出来了,下面介绍几种常用且实用的异步方法。

3.使用BeginInvoke / EndInvoke实现异步

3.1 简单的异步示例

下面看一个简单的示例: 

//使用一个有返回值的泛型委托来执行BeginInvoke
Func<string> myFunc = new Func<string>(()=>{
    Thread.Sleep(10);
    return "我是异步执行完成的返回值 当前时间:" + System.DateTime.Now.ToString();
});
IAsyncResult asynResult = myFunc.BeginInvoke(null, null);
//在异步没有完成前,可以做别的事
while (!asynResult.IsCompleted)
{
    //当不是true时,就执行这里的代码
    Console.WriteLine("当前异步是否完成:" + asynResult.IsCompleted + " 当前时间:" + System.DateTime.Now.ToString());
}
string result = myFunc.EndInvoke(asynResult);//当是true时,就将结果返回显示

Console.WriteLine(result);

 运行结果如下:

 

在异步没有完成时,可以继续工作做一些想做的事,异步完成后返回结果。

3.2 使用异步的超时 WaitOne 判断异步完成

除了上面使用IsCompleted来判断异步完成之外,也可以使用超时来判断异步的完成情况

示例如下 :

//使用一个有返回值的泛型委托来执行BeginInvoke
Func<string> myFunc = new Func<string>(()=>{
    int i = 0;
    while (i<99999999)
        ++i;
    return "异步执行完成的返回值" + (i).ToString() + " 当前时间:" + System.DateTime.Now.ToString();
   
});
IAsyncResult asynResult = myFunc.BeginInvoke(null, null);

while (!asynResult.AsyncWaitHandle.WaitOne(10, false))
    Console.Write("*");

string result = myFunc.EndInvoke(asynResult);
Console.Write("\n");
Console.WriteLine(result);

运行结果如下:

3.3 回调

毕竟上述两种等待不是一个好的方法。我们在前端开发中使用过ajax的同学肯定知道,前端中异步使用一个回调函数在异步完成后完成我们想要做的事,.NET自然也有类似的回调方法,

看示例:

           
//使用一个有返回值的泛型委托来执行BeginInvoke
Func<string> myFunc = new Func<string>(()=>{
    int i = 0;
    while (i<99999999)
        ++i;
    return "异步执行完成的返回值" + (i).ToString() + " 当前时间:" + System.DateTime.Now.ToString();
   
});
IAsyncResult asynResult = myFunc.BeginInvoke((result) =>
{
    string rst = myFunc.EndInvoke(result);
    Console.WriteLine("异步完成了,我该返回结果了!");
    Console.WriteLine(rst);
}, null);

运行结果如下 :

3.4 其它组件中的Begin\End异步方法

除了BeginInvoke / EndInvoke之外,.NET在很多类中提供了异步的方法,

如System.Net.HttpWebRequest类的BeginGetResponse和EndGetResponse方法,

这里不再一一列举了,使用方法和上面的示例类似。

 4. async/await  

.NET 5.0 以后,让异步编程变得更加简单了,我们介绍一下async和await。 

它让我们编写异步程序变得和同步一样简单,不但减少了代码量,而且不会因为异步让我们程序逻辑被打乱。 

4.1 异步方法 

下面使用async 和 await关键字来创建一个异步方法,

在第一个方法里调用第二个异步方法,

第二个异步方法中使用了多线程。

听起来很绕口,不过整个代码编写和同步方法没有什么区别,只是多一个关键字。

static void Main(string[] args)
{
    Console.WriteLine("主线程开始..");
    AsyncMethod();
    Thread.Sleep(1000);
    Console.WriteLine("主线程结束..");


    Console.ReadKey();
}

static async void AsyncMethod()
{
    Console.WriteLine("开始异步方法");
    var result = await MyMethod();
    Console.WriteLine("异步方法结束");
}

static async Task<int> MyMethod()
{
    for (int i = 0; i < 5; i++)
    {
        Console.WriteLine("异步执行" + i.ToString() + "..");
        await Task.Delay(1000); //模拟耗时操作
    }
    return 0;
}

运行结果如下: 

 

4.2 异步事件

下面使用一个WinForm应用程序来测试一下异步事件,我们创建一个同步的Click事件和一个异步的Click事件,先触发异步,然后紧接着触发同步,看一下运行结果。 

//同步事件
private void button2_Click(object sender, EventArgs e)
{
    textBox1.Text += "同步执行开始..\r\n";          
    MyMethodFirst();
    textBox1.Text += "同步执行结束..\r\n";          
}
//同事事件调用方法
int MyMethodFirst()
{
    for (int i = 0; i < 5; i++)
    {
        textBox1.Text += "同步执行" + i.ToString() + "..\r\n";               
    }
    return 0;
}

//异步事件
private async  void button3_Click(object sender, EventArgs e)
{
    textBox1.Text += "异步执行开始..====\r\n";
    await MyMethodSencond();
    textBox1.Text += "异步执行结束..====\r\n";     
}
//异步事件调用方法
async Task<int> MyMethodSencond()
{
    for (int i = 0; i < 5; i++)
    {
        textBox1.Text += "异步执行" + i.ToString() +" ..====\r\n";          
        await Task.Delay(1000); //模拟耗时操作
    }
    return 0;
}

 运行结果如下:

5. 本节要点

A.使用传统方法BeginInvoke / EndInvoke来实现异步

B.使用async/await 创建异步方法和事件

==============================================================================================

返回目录

<如果对你有帮助,记得点一下推荐哦,如有有不明白或错误之处,请多交流>

<对本系列文章阅读有困难的朋友,请先看《.net 面向对象编程基础》>

<转载声明:技术需要共享精神,欢迎转载本博客中的文章,但请注明版权及URL>

.NET 技术交流群:467189533 .NET 程序设计

==============================================================================================

转载于:https://www.cnblogs.com/yubinfeng/p/4687904.html

相关文章:

  • [转]activiti5用户任务分配
  • 数据结构:链表 链表按结点中第j个数据属性排序(冒泡排序法)
  • 批处理命令调用WINRAR对文件进行压缩
  • 线段树+树状数组+贪心 HDOJ 5338 ZZX and Permutations
  • 批处理命令拷贝文件
  • 我4年前写的第一个ruby程序
  • c# 调用c DLL 所传参数不正确
  • 离职那天我们复员——Leo网上答疑53
  • Spark工作机制-调度与任务分配
  • DT大数据梦工厂 第74讲
  • TCP SYN-Cookie背后的人和事
  • Unity3D NGUI 点击穿透问题的解决方案
  • C++ VS C#(4):枚举,结构体
  • 字节对齐问题 --- 莫名其妙的crash
  • .NET 4.0网络开发入门之旅-- 我在“网” 中央(下)
  • JavaScript 如何正确处理 Unicode 编码问题!
  • [译]Python中的类属性与实例属性的区别
  • 《Javascript高级程序设计 (第三版)》第五章 引用类型
  • classpath对获取配置文件的影响
  • css系列之关于字体的事
  • electron原来这么简单----打包你的react、VUE桌面应用程序
  • mac修复ab及siege安装
  • maya建模与骨骼动画快速实现人工鱼
  • Python进阶细节
  • 测试如何在敏捷团队中工作?
  • 大整数乘法-表格法
  • 给自己的博客网站加上酷炫的初音未来音乐游戏?
  • 聊聊hikari连接池的leakDetectionThreshold
  • 如何将自己的网站分享到QQ空间,微信,微博等等
  • 使用Tinker来调试Laravel应用程序的数据以及使用Tinker一些总结
  • 新版博客前端前瞻
  • ​Base64转换成图片,android studio build乱码,找不到okio.ByteString接腾讯人脸识别
  • ​configparser --- 配置文件解析器​
  • #LLM入门|Prompt#1.7_文本拓展_Expanding
  • #数学建模# 线性规划问题的Matlab求解
  • (1/2) 为了理解 UWP 的启动流程,我从零开始创建了一个 UWP 程序
  • (Redis使用系列) Springboot 整合Redisson 实现分布式锁 七
  • (剑指Offer)面试题34:丑数
  • (四)汇编语言——简单程序
  • (原創) 人會胖會瘦,都是自我要求的結果 (日記)
  • (转)大型网站架构演变和知识体系
  • *1 计算机基础和操作系统基础及几大协议
  • .CSS-hover 的解释
  • .net core 连接数据库,通过数据库生成Modell
  • .NET Core跨平台微服务学习资源
  • .net MVC中使用angularJs刷新页面数据列表
  • .NET Project Open Day(2011.11.13)
  • .Net调用Java编写的WebServices返回值为Null的解决方法(SoapUI工具测试有返回值)
  • .NET开发不可不知、不可不用的辅助类(一)
  • .NET框架设计—常被忽视的C#设计技巧
  • @angular/cli项目构建--Dynamic.Form
  • @JsonFormat与@DateTimeFormat注解的使用
  • @require_PUTNameError: name ‘require_PUT‘ is not defined 解决方法
  • [ Linux ] git工具的基本使用(仓库的构建,提交)
  • [ 隧道技术 ] 反弹shell的集中常见方式(二)bash反弹shell