C#异步编程

一、基础知识

1、异步编程

(1)同步方法:一个应用程序调用某个方法,等到其执行完成后才进行下一步操作。

(2)异步方法:一个程序调用某个方法,在处理完成前就返回该方法。

        同步和异步主要用于修饰方法。当一个方法被调用时,调用者需要等待该方法执行完毕并返回才能继续执行,我们称这个方法是同步方法;当一个方法被调用时立即返回,并获取一个线程执行该方法内部的业务,调用者不用等待该方法执行完毕,我们称这个方法为异步方法。

net4.0在ThreadPool的基础上推出了Task类,微软极力推荐使用Task来执行异步任务。

net5.0推出了async/await,让异步编程更为方便。

异步的优点:

       异步的好处在于非阻塞(调用线程的不会暂停执行去等待子线程完成),因此我们把一些不需要立即使用结果、较耗时的任务设为异步执行,可以提高程序的运行效率。

2、C#异步编程的三种模式

(1)基于任务的异步模式(TAP),它使用一个方法来表示异步操作的启动和完成。

(2)基于事件的异步模式(EAP),它是用于提供异步行为的基于事件的遗留模型。它需要一个具有Async后缀和一个或多个事件、事件处理程序委托类型和EventArg衍生类型。

(3)异步编程模型(APM)模式(也称为IAsyncResult(模式),它是使用IAsyncResult接口提供异步行为。

3、任务和线程的区别

(1)Thread

      用于开启一条单独的线程。

(2)Task

  • Task是一种基于任务的编程模型,它与Thread的主要区别是,Task更加方便的对线程进行调度和获取线程的执行结果;
  • Task是架构在线程之上,任务最终还要在线程去执行。
  • Task拥有线程池的优点,同时也解决了使用线程池不易控制的弊端

Task跟线程池Threadpool的功能类似,用Task开启新任务时,会从线程池中调用线程,而Thread每次实例化后都会创建一个新的线程。

Task是在ThreadPool的基础上推出的,ThreadPool中有若干数量的线程,如果有任务需要处理时,会从线程池中获取一个空闲的线程来执行任务,任务执行完毕后线程不会销毁,而是被线程池回收以供后续任务使用。当线程池中所有的线程都在忙碌时,又有新任务要处理时,线程池才会新建一个线程来处理该任务,如果线程数量达到设置的最大值,任务会排队,等待其他任务释放线程后再执行。线程池能减少线程的创建,节省开销。

ThreadPool不能控制线程的执行顺序,我们也不能获取线程池内线程取消/异常/完成的通知,即我们不能有效监控和控制线程池中的线程。

4、Task使用方法

(1)创建一个Task对象,并通过委托的方式运行某个方法

Task task=new Task(dowork);//创建Task对象,并运行方法
private void dowork()
{
  //.....
}

 (2)允许向委托运行的方法传递数据

Action <object> action;
action =doworkObject;//定义要执行的方法
object parameterData=...;//定义要传递的参数
Task task=new Task(action,parameterData);
task.start();//启动方法

private void doworkObject(object o)
{
  //......
}

(3)使用Task类提供的静态方法创建和运行任务

Task task=Task.Run(()=>doWork());//创建Task对象,并运行方法
private void dowork()
{
  //.....
}

二、简单异步编程

1、async和await

C#使用关键字async和await实现异步方法,async指出方法可能要异步执行操作,而await指定异步操作的地点。

(1)async

用async修饰一个方法,表明这个方法时异步的,该方法的返回类型有void、Task和Task<TResult>,方法的内部必须含有await修饰,否则该方法依然是同步方法。

(2)async和await结构的执行顺序

第一步:调用方法,调用一个异步方法,然后在异步方法执行器任务的时候继续顺序执行其他语句。

第二步:执行异步方法,异步方法执行里面的工作,然后立刻返回到调用方法。

第三步:执行await,用于异步方法内部,指出异步执行的任务,一个异步方法可能包含多个await表达式。

2、应用举例


        private async void btnClick_Click(object sender, EventArgs e)
        {
            long length = await AccessWebAsync();
           
            // 这里可以做一些不依赖回复的操作
            OtherWork();

            this.richTextBox1.Text += String.Format("\n 回复的字节长度为:  {0}.\r\n", length);
            txbMainThreadID.Text = Thread.CurrentThread.ManagedThreadId.ToString();
        }

        // 使用C# 5.0中提供的async 和await关键字来定义异步方法
        // 从代码中可以看出C#5.0 中定义异步方法就像定义同步方法一样简单。
        // 使用async 和await定义异步方法不会创建新线程,
        // 它运行在现有线程上执行多个任务.
        // 此时不知道大家有没有一个疑问的?在现有线程上(即UI线程上)运行一个耗时的操作时,
        // 为什么不会堵塞UI线程的呢?
        // 这个问题的答案就是 当编译器看到await关键字时,线程会
        private async Task<long> AccessWebAsync()
        {
            MemoryStream content = new MemoryStream();

            // 对MSDN发起一个Web请求
            HttpWebRequest webRequest = WebRequest.Create("http://msdn.microsoft.com/zh-cn/") as HttpWebRequest;
            if (webRequest != null)
            {
                // 返回回复结果
                using (WebResponse response = await webRequest.GetResponseAsync())
                {
                    using (Stream responseStream = response.GetResponseStream())
                    {
                        await responseStream.CopyToAsync(content);
                    }
                }
            }

            txbAsynMethodID.Text = Thread.CurrentThread.ManagedThreadId.ToString() ;
            return content.Length;
        }

        private void OtherWork()
        {
            this.richTextBox1.Text += "\r\n等待服务器回复中.................\n";
        }

参考文献:

【1】https://blog.csdn.net/u013477973/article/details/71081836

【2】https://www.cnblogs.com/wyy1234/p/9172467.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值