C#异步编程的⼏种⽅式
在异步程序中,程序代码不需要严格按照编写时的顺序执⾏
为了改善代码性能,有时候需要在⼀个新的线程中运⾏⼀部分代码
有时候⽆需创建新的线程,但为了更好的利⽤单个线程的能⼒,需要改变代码的执⾏顺序
也就是说:
异步编程赋予代码⾮顺序执⾏的能⼒,让程序能够在部分耗时操作的同时,⼲其他的事情
⼀、通过委托实现异步
如果委托对象在调⽤列表中只有⼀个⽅法(引⽤⽅法),它就可以异步执⾏这个⽅法
委托类有 BeginInvoke,EndInvoke ⽅法,可以⽤以下⽅式使⽤:
当调⽤ BeginInvoke ⽅法时,它开始在⼀个独⽴线程上执⾏引⽤⽅法,并⽴即返回到原始线程;原始线程可以继续运⾏,⽽引⽤⽅法会在线程池⼤的线程中并⾏执⾏当程序希望获取已完成的异步⽅法的结果时,可以检查 BeginInvoke 返回的 IAsyncResult 的 IsCompleted 属性,或者调⽤ EndInvoke ⽅法等待
委托的完成
使⽤这⼀过程有三种标准模式,区别在于:原始线程如何知道发起的线程已经完成
⼀直等待到完成模式(wait until done):
  原始线程发起异步⽅法并做了⼀些其他处理后,原始线程中断并等待异步⽅法完成后再继续
轮询模式(polling):
  原始线程定期检查发起的异步⽅法线程是否完成,如果没有则继续做其他事情
回调模式(callback):
  原始线程⼀直执⾏,⽆需等待,当发起的线程中引⽤⽅法完成后,发起的线程就调⽤回调⽅法,调⽤ EndInvoke 之前处理异步⽅法的结果
1static void Main(string[] args)
2        {
3            Console.WriteLine("===== 同步调⽤ =====");
4            AddDel del = new AddDel(Add);
5int 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// 委托
23public delegate int AddDel(int a, int b);
24// 加法计算
25static int Add(int a, int b)
26        {
27            Console.WriteLine("开始计算:" + a + "+" + b);
28// 模拟运⾏时间
29            Thread.Sleep(2000);
30            Console.WriteLine("计算完成!");
31return a + b;
32        }
33// 回调函数
34static void AddAsync(IAsyncResult ar)
35        {
36            AddDel del = ((AsyncResult)ar).AsyncDelegate as AddDel;
37            Console.WriteLine("计算结果:" + del.EndInvoke(ar));
38            Console.WriteLine(ar.AsyncState);await和async使用方法
39        }
⼆、通过 Task 实现异步
Task 类通常是以异步⽅式执⾏的单个操作,更适合在后台完成的⼀些⼩任务
由于 Task 对象执⾏的⼯作通常在线程池的线程上异步执⾏,⽽不是在程序主线程上同步执⾏
因此可以使⽤ Status 属性,还可以使⽤ IsCancele、IsCompleted 和 IsFaulted 属性来确认任务的状态
⼤多数情况下,lambda 表达式⽤于指定的任务是执⾏的⼯作
1static void Main(string[] args)
2        {
3            Console.WriteLine("主线程正在执⾏业务处理!");
4// 创建任务
5            Task task = new Task(() =>
6            {
7                Console.WriteLine("使⽤Task执⾏异步操作:");
8for (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 关键字定义的异步⽅法简称为 "异步⽅法"
1static 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
14public static async void AsyncTest()
16            Console.WriteLine("开始执⾏异步操作:");
17// await 不会开启新的线程
18// 需要⾃⼰创建Task,才会真正的去创建线程
19//await new Program().AsyncTaskFun();
20await Task.Run(() =>
21            {
22new Program().AsyncTaskFun();
23            });
24            Console.WriteLine("异步操作执⾏完成!");
25        }
26
27public async Task<int> AsyncTaskFun()
28        {
29            Console.WriteLine("异步操作正在执⾏:");
30for (int i = 1; i <= 10; i++)
31            {
32                Console.WriteLine("操作执⾏:" + i * 10 + "%");
33                Thread.Sleep(100);
34            }
35return2;
36        }
四、通过 BackgroundWorker 实现异步
有时候我们需要在后台新建⼀个线程默默完成⼀项⼯作,过程中时不时同主线程进⾏通信,这就是 BackgroundWorker 的主要任务BackgroundWorker 类允许在单独的线程上执⾏某个可能导致⽤户界⾯(UI)停⽌响应的耗时操作,并且想要⼀个响应式的UI来反应当前耗时操作的进度  :
1public partial class Form1 : Form
2    {
3// BackgroundWorker实例
4        BackgroundWorker bw = new BackgroundWorker();
5
6public 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// 进度条变化
17private void bw_ProgressChanged(Object sender, ProgressChangedEventArgs e)
18        {
19            progressBar1.Value = e.ProgressPercentage;
20            label1.Text = e.UserState.ToString();
21            label1.Update();
22        }
23// 后台任务完成
24private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
25        {
26            MessageBox.Show("后台操作执⾏完成!");
27        }
28// 后台具体任务
29private void bw_DoWork(object sender, DoWorkEventArgs e)
30        {
31            BackgroundWorker bw = sender as BackgroundWorker;
32int num = 101;
33for (int i = 0; i < num; i++)
34            {
35if (bw.CancellationPending)
36                {
37                    bw.ReportProgress(i, $"当前进度{i}%, 已停⽌!");
38return;
39                }
40                bw.ReportProgress(i, $"当前进度{i}%");
41                Thread.Sleep(100);
43return;
44        }
45// 开始按钮
46private void button1_Click(object sender, EventArgs e)
47        {
48if (bw.IsBusy) return;
49            bw.RunWorkerAsync();
50        }
51// 停⽌按钮
52private void button2_Click(object sender, EventArgs e)
53        {
54            bw.CancelAsync();
55        }
56    }
*** |  以上内容仅为学习参考、学习笔记使⽤  | ***

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。