C# 异步编程

本文深入探讨了三种异步编程模式:异步模式、基于事件的异步模式和基于任务的异步模式,包括.NET Framework下的委托实现、.NET 2.0后的事件驱动和.NET 4.0后的任务编程,以及.NET 4.5引入的await/async关键字使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

        本节将介绍3中不同的异步编程:异步模式、基于事件的异步模式和基于任务的异步模式

1.异步模式

        通过委托来实现异步(在委托类型中定义了BeginInvoke()和EndInvoke()两个方法),使用回调函数。注:运行在.NET FrameWork框架下

1.1异步方法--传1个参数

    class Program
    {
        static void Main(string[] args)
        {
            //通过委托来实现异步编程的(在委托类型中定义了BeginInvoke()和EndInvoke()两个方法)
            string i = "参数";
            Console.WriteLine("调用异步方法前");
            PostAsync(i);
            Console.WriteLine("调用异步方法后");

            Console.ReadKey();
        }

        delegate void AsyncFoo(string i);//定义委托
        private static void PostAsync(object i)
        {
            AsyncFoo caller = Myfunc;//声明委托
            caller.BeginInvoke(i.ToString(), FooCallBack, caller);//绑定委托
        }

        //回调方法
        private static void FooCallBack(IAsyncResult ar)
        {
            var caller = (AsyncFoo)ar.AsyncState;
            caller.EndInvoke(ar);
        }

        /// <summary>
        /// 执行业务逻辑的方法
        /// </summary>
        /// <param name="i">调用异步时传过来的参数</param>
        private static void Myfunc(string i)
        {
            Console.WriteLine("通过委托来实现异步编程的");
        }
        
    }

运行结果:

1.2 异步方法--传2个或多个参数

    class Program
    {
        static void Main(string[] args)
        {
            //通过委托来实现异步编程的(在委托类型中定义了BeginInvoke()和EndInvoke()两个方法)
            Console.WriteLine("调用异步方法前");
            PostAsync("参数1", "参数2");
            Console.WriteLine("调用异步方法后");

            Console.ReadKey();
        }

        delegate void AsyncFoo(string i, string p);//定义委托
        private static void PostAsync(string i, string p)
        {
            AsyncFoo caller = Myfunc;//声明委托

            //FooCallBack,caller为额外的参数
            caller.BeginInvoke(i, p, FooCallBack, caller);//绑定委托
        }

        /// <summary>
        /// 回调函数
        /// </summary>
        /// <param name="ar">委托执行完毕后EndInvoke的返回值</param>
        private static void FooCallBack(IAsyncResult ar)
        {
            var caller = (AsyncFoo)ar.AsyncState;
            caller.EndInvoke(ar);
        }

        /// <summary>
        /// 执行业务逻辑的方法
        /// </summary>
        /// <param name="i">参数1</param>
        /// <param name="p">参数2</param>
        private static void Myfunc(string i, string p)
        {
            Console.WriteLine(i);
            Console.WriteLine(p);
        }
        
    }

运行结果:

2. 基于事件的异步模式

         .NET2.0之后推出了基于事件的异步模式,更便于处理UI更新。设计思路是在同步方法名称的后面加上了一个“Async”的后缀。这个方法在此就先不详解了,看下看更加方便的异步技术

3. 基于任务的异步模式

3.1 task

      .NET4.0的新特性,便于基于任务的编程,完成多线程控制的目标。

    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("主线程,线程ID:" + Thread.CurrentThread.ManagedThreadId);
            //Task方式一
            Task task1 = new Task(() => TaskFunc1());
            task1.Start();

            //Task方式二
            var result = Task.Run<string>(() => { return TaskFunc2(); });
            Console.WriteLine(result.Result);

            Console.ReadKey();
        }

        private static void TaskFunc1()
        {
            Task.Delay(1000).Wait();
            Console.WriteLine("Task方式一开启的线程ID:" + Thread.CurrentThread.ManagedThreadId);
        }

        private static string TaskFunc2()
        {
            return "Task方式二开启的线程ID:" + Thread.CurrentThread.ManagedThreadId;
        }
        
    }

运行结果:

3.2 await async——使用单个异步方法

        .NET4.5的新特性,该模式定义了一个带"Async"后缀的方法,并返回一个Task<string>类型。

3.2.1 控制台示例

    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("主线程,线程ID:" + Thread.CurrentThread.ManagedThreadId);
            var result1 = AsyncFunc1();//调用异步方法
            Console.WriteLine(result1.Result);

            Console.ReadKey();
        }

        /// <summary>
        /// 创建任务
        /// </summary>
        /// <returns></returns>
        private static async Task<string> AsyncFunc1()
        {
            return await Task.Run(() =>
            {
                Task.Delay(1000).Wait();
                Console.WriteLine("await/async线程ID: {0}", Thread.CurrentThread.ManagedThreadId);
                return "这是返回值";
            });
        }
    }

运行结果:

3.2.2 WinForm窗体示例1

        private void button1_Click(object sender, EventArgs e)
        {
            Dog dog = new Dog();
            Task task = dog.DoSomthingAsync().ContinueWith(OnDoSomthingIsComplete);
        }
        
        ///
        ///任务完成后要执行的方法,更新UI
        ///
        private void OnDoSomthingIsComplete(Task t)
        {
            Action action = () => {
                textBox1.Text = "任务完成后显示这段文字到UI控件";
            };
            textBox1.Invoke(action);
        }

        /// <summary>
        /// Dog类
        /// </summary>
        public class Dog
        {
            public Task DoSomthingAsync()
            {
                Task task = Task.Run(() => {
                    Console.WriteLine("后台任务开始运行");
                    Thread.Sleep(5000);
                    Console.WriteLine("后台任务运行结束");
                });
                return task;
            }
        }

运行结果:

3.2.3 WinForm窗体示例2

        private async void button1_Click(object sender, EventArgs e)
        {
            checkBox1.Checked = await MoveArm();
        }

        /// <summary>
        /// 创建任务
        /// </summary>
        /// <returns></returns>
        private async Task<bool> MoveArm()
        {
            return await Task<bool>.Run(async() => 
            {
                await Task.Delay(5000);//异步 等待Task完成执行过程
                return true;
            });
        }
        /************************或者*************************/
        /// <summary>
        /// 创建任务
        /// </summary>
        /// <returns></returns>
        private async Task<bool> MoveArm()
        {
            return await Task<bool>.Run(() => 
            {
                Task.Delay(5000).Wait();//等待Task完成执行过程
                return true;
            });
        }

运行结果:

3.3 await async——使用多个异步方法

3.3.1 如果一个异步方法依赖于另外一个异步方法,则按顺序调用异步方法

         这时候await关键字就非常有用,每个异步方法都得使用await关键字。

3.3.2 如果一个异步方法不依赖与另外一个异步方法,使用组合器

        这时候每个异步方法可以不使用await关键字,而是把每个异步方法的返回结果赋值给Task变量,然后使用Task的WhenAll组合器或WhenAny组合器,这样运行可以更快。

        其中,WhenAll方法返回Task,是在所有的传入方法的任务都完成了才会返回Task。从WhenAny方法返回的Task,是在其中一个传入方法的任务完成了就会返回Task。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值