前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >c#异步编程实现

c#异步编程实现

作者头像
MaybeHC
发布2024-04-23 19:20:35
970
发布2024-04-23 19:20:35
举报
文章被收录于专栏:技术之路技术之路

同步&异步

既然说到异步编程那就说下异步编程和同步编程的区别。 同步:简单来说就是按顺序执行,例如登录过程必须输入用户名、密码再点击登录 第一步:输入用户名 第二步:输入密码 第三部:点击登录 这就是一个同步过程 异步:异步可以说是同时进行多个任务,相互不干扰,第二个任务的执行不需要等待第一个任务执行。 例如: 下载一个Oracle的安装包,安装过得人应该知道 Oracle的安装包一般是有两个构成,必须两个都下载然后解压在一起才可以开始安装。这里我们下载的过程肯定是不需要先下载安装包1再下载安装包2,而是一起下载,等两个都下载好了进行安装。 我们可以对比下异步和同步所需时间,还是以下载Oracle安装包为例。 假设下载安装包1需要6s,下载安装包2需要4s 同步的操作: 一.下载安装包1 二.下载安装包2 所需时间:6+4 =10s 异步的操作:同时下载安装包1安装包2(排除网络原因) 所需时间应算最长下载时间,所需时间:6s

代码实现

简单异步实现

下面我们直接用代码来呈现异步过程,用一个小demo来实现。

在这里插入图片描述
在这里插入图片描述
代码语言:javascript
复制
    public partial class Form1 : Form
    {
        //异步编程:基于委托实现
        public Form1()
        {
            InitializeComponent();
        }
        //[1]定义一个委托
        public delegate int MyCalulator(int num);
        //[2]根据委托实现方法
        private int ExecuteTask1(int num)
        {
            System.Threading.Thread.Sleep(5000);
            return num * num;
        }
        private int ExecuteTask2(int num)
        {
            return num * num;
        }
        //同步调用
        private void button1_Click(object sender, EventArgs e)
        {
            this.label1.Text = ExecuteTask1(10).ToString();
            this.label2.Text = ExecuteTask2(10).ToString();
        }

        //[3]异步调用
        private void button2_Click(object sender, EventArgs e)
        {
            MyCalulator objMycal = ExecuteTask1;//定义委托变量,并引用对应方法
            //1.异步调用任务 实际调用参数 回调函数 回调函数入参
            IAsyncResult result =objMycal.BeginInvoke(10,null,null);
            this.label1.Text = "正在计算请稍等。。。";
            //2.并行执行其他任务
            this.label2.Text = ExecuteTask2(200).ToString();
            //3.获取异步执行结果
            int r = objMycal.EndInvoke(result);
            this.label1.Text = r.ToString();
        }
    }

异步是基于委托实现的所以我们第一步需要定义一个委托

代码语言:javascript
复制
 public delegate int MyCalulator(int num);

第二步根据委托实现方法

代码语言:javascript
复制
private int ExecuteTask1(int num)
        {
            System.Threading.Thread.Sleep(5000);
            return num * num;
        }

第三部编写异步方法

代码语言:javascript
复制
private void button2_Click(object sender, EventArgs e)
        {
        	//通过委托调用方法ExecutrTask1
            MyCalulator objMycal = ExecuteTask1;//定义委托变量,并引用对应方法
            //1.异步调用任务 实际调用参数 回调函数 回调函数入参
            IAsyncResult result =objMycal.BeginInvoke(10,null,null);
            this.label1.Text = "正在计算请稍等。。。";
            //2.并行执行其他任务
            this.label2.Text = ExecuteTask2(200).ToString();
            //3.获取异步执行结果
            int r = objMycal.EndInvoke(result);
            this.label1.Text = r.ToString();
        }

编写异步方法的流程在注释里都写出来了,下来重点介绍下其中的几个方法 BeginInvoke函数

代码语言:javascript
复制
IAsyncResult result =objMycal.BeginInvoke(10,null,null);

委托类型的BeginInvoke(<输入和输出变量>,AsyncCallBack callback , object ayncState)方法 :异步调用的核心 第一个参数 表示委托对应的方法实参 第二个参数 回调函数,表示异步调用结束后,自动调用的方法 第三个参数 用于向回到函数提供相关的参数信息 返回值:IAsyncResult->异步操作状态接口,封装了异步执行中的参数

在这里我们只是实现一个简单的异步,并没有使用回调方法,而是直接取了返回值。在后面的文章中会使用回调方法。 下面我们可以看下demo的运行情况

在这里插入图片描述
在这里插入图片描述

可以看到单机同步后因为第一个计算方法需求等待,所以第二个结果基本是与第一个结果同时出现的,而使用异步结果2直接被计算了出来,之后结果1经过等待时间后被计算。

异步方法采用回调函数

还是用一个demo来讲解异步方法使用回调函数,先看下demo的运行效果

在这里插入图片描述
在这里插入图片描述

这里我把输出放在了控制台上,先看代码吧

代码语言:javascript
复制
 public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            objMyCal = new MyCalculator(ExecuteTask);
        }
        //【3】创建委托变量
        private delegate int MyCalculator(int num, int ms);
        private int ExecuteTask(int num,int ms)
        {
            System.Threading.Thread.Sleep(ms);
            return num * num;
        }
        //【1】声明委托
        MyCalculator objMyCal = null;
        private void button1_Click(object sender, EventArgs e)
        {
            //发布任务
            for(int i = 1; i < 11; i++)
            {
                //开始异步执行
                objMyCal.BeginInvoke(10 * i, 1000 * i, MyCallBack,i);
                //到最后一个参数i给回调函数的字段AsyncState赋值,如果数据很多可以定义成类或结构
            }
        }

        private void MyCallBack(IAsyncResult result)
        {
            int res = objMyCal.EndInvoke(result);
            //显示异步调用结果:result.AsyncState字段用来封装回调函数自定义参数,object类型
            Console.WriteLine($"第{result.AsyncState.ToString()}个计算结果为{res}");
        }
    }

通过上面的代码可以看到,我们每次给睡眠时间增加1000毫秒,如果不采用异步的话,执行时间应该是1+2+3+…+10=55s.然而我们这里采用异步只需要10s左右,大部分流程与上面相同,有不同之处的是这里

代码语言:javascript
复制
objMyCal.BeginInvoke(10 * i, 1000 * i, MyCallBack,i);

这里的第三个参数位置我们添加了回调方法MyCallBack

代码语言:javascript
复制
 private void MyCallBack(IAsyncResult result)
        {
            int res = objMyCal.EndInvoke(result);
            //显示异步调用结果:result.AsyncState字段用来封装回调函数自定义参数,object类型
            Console.WriteLine($"第{result.AsyncState.ToString()}个计算结果为{res}");
        }

在第四个参数位置输入了给回调函数使用的参数,这里的类型是object型,可以传入任何类型的参数,这个参数传入后会保存在IAsyncResult的AsyncState中,在回到函数中我们也进行了调用的示范,在如下这句话中result.AsyncState.ToString()

代码语言:javascript
复制
Console.WriteLine($"第{result.AsyncState.ToString()}个计算结果为{res}");

这段代码就是使用了回调函数的异步调用。

异步编程总结

1.异步编程是建立在委托的基础上的一种编程的方法 2.异步调用的每个方法都是独立的线程中执行的。因此,本质上就是一种多线程程序,是简化的多线程 3.比较适合在后头运行较为耗时的《简单任务》,并且任务之间要求相互独立,任务中不应该有直接访问可视化控件的代码 3.如果后台任务要求必须按照特定的顺序执行,或者访问共享资源,则异步编程不太适合,应该选择多线程开发技术。

本文参与?腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2024-04-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客?前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与?腾讯云自媒体分享计划? ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 同步&异步
  • 代码实现
    • 简单异步实现
      • 异步方法采用回调函数
        • 异步编程总结
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
        http://www.vxiaotou.com