C#实现异步方式

2023-09-14 09:51:11

在异步程序中,程序代码不需要严格按照编写时的顺序执行

为了改善代码性能,有时候需要在一个新的线程中运行一部分代码

有时候无需创建新的线程,但为了更好的利用单个线程的能力,需要改变代码的执行顺序

也就是说:

异步编程赋予代码非顺序执行的能力,让程序能够在部分耗时操作的同时,干其他的事情

一、通过委托实现异步

如果委托对象在调用列表中只有一个方法(引用方法),它就可以异步执行这个方法

委托类有 BeginInvoke,EndInvoke 方法,可以用以下方式使用:

  • 当调用 BeginInvoke 方法时,它开始在一个独立线程上执行引用方法,并立即返回到原始线程;原始线程可以继续运行,而引用方法会在线程池大的线程中并行执行
  • 当程序希望获取已完成的异步方法的结果时,可以检查 BeginInvoke 返回的 IAsyncResult 的 IsCompleted 属性,或者调用 EndInvoke 方法等待委托的完成

使用这一过程有三种标准模式,区别在于:原始线程如何知道发起的线程已经完成

  • 一直等待到完成模式(wait until done):

  原始线程发起异步方法并做了一些其他处理后,原始线程中断并等待异步方法完成后再继续

  • 轮询模式(polling):

  原始线程定期检查发起的异步方法线程是否完成,如果没有则继续做其他事情

  • 回调模式(callback):

  原始线程一直执行,无需等待,当发起的线程中引用方法完成后,发起的线程就调用回调方法,调用 EndInvoke 之前处理异步方法的结果

复制代码

 1         static void Main(string[] args)
 2         {
 3             Console.WriteLine("===== 同步调用 =====");
 4             AddDel del = new AddDel(Add);
 5             int result = del.Invoke(11, 89);
 6             Console.WriteLine("计算结果:" + result);
 7             Console.WriteLine("继续削铅笔...\n");
 8             Console.ReadKey();
 9 
10             Console.WriteLine("===== 异步调用 =====");
11             IAsyncResult result_1 = del.BeginInvoke(22, 78, null, null);
12             Console.WriteLine("继续削铅笔...");
13             Console.WriteLine("计算结果:" + del.EndInvoke(result_1));
14             Console.ReadKey();
15 
16             Console.WriteLine("\n===== 异步回调 =====");
17             del.BeginInvoke(33, 67, new AsyncCallback(AddAsync), "AsyncState:OK");
18             Console.WriteLine("继续削铅笔...");
19             Console.ReadKey();
20         }
21 
22         // 委托
23         public delegate int AddDel(int a, int b);
24         // 加法计算
25         static int Add(int a, int b)
26         {
27             Console.WriteLine("开始计算:" + a + "+" + b);
28             // 模拟运行时间
29             Thread.Sleep(2000);
30             Console.WriteLine("计算完成!");
31             return a + b;
32         }
33         // 回调函数
34         static void AddAsync(IAsyncResult ar)
35         {
36             AddDel del = ((AsyncResult)ar).AsyncDelegate as AddDel;
37             Console.WriteLine("计算结果:" + del.EndInvoke(ar));
38             Console.WriteLine(ar.AsyncState);
39         }

复制代码

二、通过 Task 实现异步

Task 类通常是以异步方式执行的单个操作,更适合在后台完成的一些小任务

由于 Task 对象执行的工作通常在线程池的线程上异步执行,而不是在程序主线程上同步执行

因此可以使用 Status 属性,还可以使用 IsCancele、IsCompleted 和 IsFaulted 属性来确认任务的状态

大多数情况下,lambda 表达式用于指定的任务是执行的工作

🙌🌰:

复制代码

 1         static void Main(string[] args)
 2         {
 3             Console.WriteLine("主线程正在执行业务处理!");
 4             // 创建任务
 5             Task task = new Task(() =>
 6             {
 7                 Console.WriteLine("使用Task执行异步操作:");
 8                 for (int i = 0; i <= 10; i++)
 9                 {
10                     Console.WriteLine("操作执行:" + i * 10 + "%");
11                     Thread.Sleep(100);
12                 }
13                 Console.WriteLine("Task异步操作执行完成!");
14             });
15             // 启动任务,并安排到当前任务队列线程中执行任务
16             task.Start();
17             Thread.Sleep(500);
18             Console.WriteLine("主线程正在执行其他业务!");
19             Console.ReadKey();
20         }

复制代码

三、通过 await/async 实现异步

C# 中的 Async 和 Await 关键字是异步编程的核心

通过这两个关键字,可以使用 .NET Framework、.NET Core 或 Windows 运行时中的资源,轻松创建异步方法(几乎与创建同步方法一样轻松)

而使用 Async 关键字定义的异步方法简称为 "异步方法"

🙌🌰: 

复制代码

 1         static void Main(string[] args)
 2         {
 3             Console.WriteLine("主线程正在执行第一项业务!");
 4             AsyncTest();
 5             Thread.Sleep(300);
 6             Console.WriteLine("主线程正在执行第二项业务!");
 7             Thread.Sleep(300);
 8             Console.WriteLine("主线程正在执行第三项业务!");
 9             Thread.Sleep(500);
10             Console.WriteLine("主线程正在执行最后一项业务!");
11             Console.ReadKey();
12         }
13 
14         public static async void AsyncTest()
15         {
16             Console.WriteLine("开始执行异步操作:");
17             // await 不会开启新的线程
18             // 需要自己创建Task,才会真正的去创建线程
19             //await new Program().AsyncTaskFun();
20             await Task.Run(() =>
21             {
22                 new Program().AsyncTaskFun();
23             });
24             Console.WriteLine("异步操作执行完成!");
25         }
26 
27         public async Task<int> AsyncTaskFun()
28         {
29             Console.WriteLine("异步操作正在执行:");
30             for (int i = 1; i <= 10; i++)
31             {
32                 Console.WriteLine("操作执行:" + i * 10 + "%");
33                 Thread.Sleep(100);
34             }
35             return 2;
36         }

复制代码

四、通过 BackgroundWorker 实现异步

有时候我们需要在后台新建一个线程默默完成一项工作,过程中时不时同主线程进行通信,这就是 BackgroundWorker 的主要任务

BackgroundWorker 类允许在单独的线程上执行某个可能导致用户界面(UI)停止响应的耗时操作,并且想要一个响应式的UI来反应当前耗时操作的进度

🙌🌰:

复制代码

 1     public partial class Form1 : Form
 2     {
 3         // BackgroundWorker实例
 4         BackgroundWorker bw = new BackgroundWorker();
 5 
 6         public Form1()
 7         {
 8             InitializeComponent();
 9             bw.WorkerReportsProgress = true;
10             bw.WorkerSupportsCancellation = true;
11             bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
12             bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
13             bw.DoWork += new DoWorkEventHandler(bw_DoWork);
14             progressBar1.Maximum = 100;
15         }
16         // 进度条变化
17         private void bw_ProgressChanged(Object sender, ProgressChangedEventArgs e)
18         {
19             progressBar1.Value = e.ProgressPercentage;
20             label1.Text = e.UserState.ToString();
21             label1.Update();
22         }
23         // 后台任务完成
24         private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
25         {
26             MessageBox.Show("后台操作执行完成!");
27         }
28         // 后台具体任务
29         private void bw_DoWork(object sender, DoWorkEventArgs e)
30         {
31             BackgroundWorker bw = sender as BackgroundWorker;
32             int num = 101;
33             for (int i = 0; i < num; i++)
34             {
35                 if (bw.CancellationPending)
36                 {
37                     bw.ReportProgress(i, $"当前进度{i}%, 已停止!");
38                     return;
39                 }
40                 bw.ReportProgress(i, $"当前进度{i}%");
41                 Thread.Sleep(100);
42             }
43             return;
44         }
45         // 开始按钮
46         private void button1_Click(object sender, EventArgs e)
47         {
48             if (bw.IsBusy) return;
49             bw.RunWorkerAsync();
50         }
51         // 停止按钮
52         private void button2_Click(object sender, EventArgs e)
53         {
54             bw.CancelAsync();
55         }
56     }

复制代码

更多推荐

心理健康数据集:mental_health_chatbot_dataset

一.数据集描述1.数据集摘要该数据集包含与心理健康相关的问题和答案的对话对,以单一文本形式呈现。数据集是从流行的医疗博客(如WebMD、MayoClinic和HealthLine)、在线常见问题等来源精选而来的。所有问题和答案都经过匿名化处理,以删除任何个人身份信息(PII),并经过预处理以删除任何不必要的字符。2.语

RabbitMQ 消息应答

每日一句物是人非事事休,欲语泪先流。概述为了保证消息在发送过程中不丢失,RabbitMQ引入了消息应答机制,消费者在接收到消息并且处理该消息后,告诉RabbitMQ它已经处理了,RabbitMQ可以把消息删除了。自动应答消息发送后立即被认为已经传送成功,这种模式需要在高吞吐量和数据传输安全性方面做权衡。因为这种模式有两

【评论内容关键词提取】多种主流提取算法与大模型测试

文章目录1.写在前面2.TextRank关键词提取算法3.TFIDF算法4.jionlp算法5.sklearn算法6.Rake算法7.hanlp情感分析8.大语言模型1.写在前面做过舆情项目或文本内容情感分析的大家都知道,我们要从大量的文本内容中提取核心短语或者关键词!最近我们的爬虫项目中正好遇到了这么一个需求,我们收

服务器环境的关键组成部分

服务器环境是指服务器硬件和软件组成的整体环境,包括操作系统、网络配置、数据库、Web服务器软件、应用程序等。它提供了服务器运行和支持所需的基本条件和组件。以下是服务器环境中的一些关键组成部分:操作系统:服务器环境通常基于某种操作系统,如Linux、WindowsServer等。操作系统提供了服务器的基本功能和管理能力,

css知识学习系列(3)-每天10个知识点

目录1.伪类与伪元素在CSS中,伪类和伪元素有什么区别?请举例说明。2.文字与字体在CSS中,如何设置文字的大小和字体?你如何加载外部字体?3.布局在CSS中,你如何对元素进行垂直居中?4.动画与过渡你能举一个使用CSS中的动画和过渡的例子吗?并解释它的工作原理。5.重叠与层叠在CSS中,“position”属性对元素

vue+electron一键入门

前言帮公司弄了一个vue+electron项目,里面用到了axios、element-ui、ue-router、js-md5、sqlite3这些依赖库,其中sqlite3比较难搞下面会详细展开来讲,同时也涉及打包(window包、mac包)开始其实项目整体没啥好讲,我就讲一下数据库的封装、打包配置注意事项即可sqlit

K8S:pod资源限制及探针

文章目录一.pod资源限制1.pod资源限制方式2.pod资源限制指定时指定的参数(1)request资源(2)limit资源(3)两种资源匹配方式3.资源限制的示例(1)官网示例(2)Pod和容器的资源请求和限制格式(3)CPU资源单位介绍(4)内存资源单位(5)资源限制示例1:(6)资源限制示例2:二.健康检查:又

9.基于粤嵌gec6818开发板小游戏2048的算法实现

2048源码:感兴趣的可以去了解一下2048优化算法:基于蒙特卡罗树搜索的_2048_游戏优化算法_刘子正#include<stdio.h>#include<sys/types.h>#include<sys/stat.h>#include<fcntl.h>#include<sys/mman.h>#include<lin

leetcode刷题--链表

文章目录1.203移除的元素2.237删除链表中的节点3.19删除链表的倒数第N个节点4.430扁平化多级双向链表5.61旋转链表6.24两两交换链表中的节点7.206反转链表8.92反转链表II9.25K个一组翻转链表10.21合并两个有序链表11.23合并k个升序链表12.2两数相加13.445两数相加II题目分类

LLM - 大模型速递 InternLM-20B 快速入门

目录一.引言二.模型简介1.模型特性2.模型评测三.模型尝试1.模型参数2.generate与chat3.模型微调四.总结一.引言一早醒来国产开源大模型又添一员猛将,书生-浦语大模型InternLM-20B大模型发布并开源,这里字面翻译是实习生大模型,比较有意思。该模型由上海人工智能实验室与商汤科技联合香港中文大学和复

【第57篇】DEiT:通过注意力训练数据高效的图像transformer &蒸馏

摘要最近,纯基于注意力的神经网络被证明可以解决图像理解任务,如图像分类。这些高性能的是使用大型基础设施预先训练数以亿计的图像,从而限制了它们的采用。本文仅通过在Imagenet上训练,产生有竞争力的无卷积transformer。我们用一台电脑在不到3天的时间里训练它们。所提出的参考视觉transformer(86M参数

热文推荐