当前位置:   article > 正文

(十七)Async异步和多线程-语言进阶1_异步多线程

异步多线程

一、进程-线程-多线程,同步和异步

1.概念

  1. 进程:进程是一个程序运行时,占用全部计算资源的总和,指在系统中正在运行的一个应用程序;程序一旦运行就是进程;或者更专业化来说:进程是指程序执行时的一个实例,即它是程序已经执行到课中程度的数据结构的汇集。从内核的观点看,进程的目的就是担当分配系统资源(CPU时间、内存等)的基本单位。

  2. 线程:线程是程序执行流的最小单位,系统分配处理器时间资源的基本单元,或者说进程之内独立执行的一个单元执行流。任何操作都是由线程完成的;线程是依托于进程存在的,一个进程可以包含多个线程;线程也可以有自己的计算资源;
    进程——资源分配的最小单位,线程——程序执行的最小单位。

  3. 多线程:多个执行流同时运行。
    (1) CPU太快了,分时间片–上下文切换(加载环境–计算–保存环境)微观角度,一个核同一时刻只能执行一个线程;宏观的来说是多线程并发
    (2) 名CPU多核可以独立工作,例如我们常说的 “4核8线程”–其中核是物理的核 8线程是指虚拟核,并不是上述我们所说的线程。

  4. Thread:是c#语言对线程对象的封装

2.同步和异步

  1. 同步:完成计算之后在进入下一行
  2. 异步:不会等待方法的完成,会直接进入下一行,不会阻塞。
    例如我们举一个贴切的例子,
    同步:
    “你和朋友去吃饭,但他有点忙,你就等他忙完一起吃,这就是同步方法”
    异步:
    “你和朋友去吃饭,但他有点忙,你就自己先去吃,他忙完自己再去吃,这就是异步方法”

3.异步与多线程异同点

  1. 异步和多线程都可以达到避免调用线程阻塞的目的
  2. 异步操作在完成await操作后,会发出完成通知,并释放占用的线程,之后系统调用线程池中空余的线程来进行await之后的操作,减少了线程负担。
  3. 而多线程编程会在整个任务中一直占用线程造成资源浪费。比如DMA(直接存储器访问)操作,允许硬件可以不通过CPU而直接与内存数据进行交互,在这时闲置的线程无法被释放,造成了资源浪费。(使用异步可以避免)

二、委托启动异步调用

下面我们可以通过一个示例看一下,分别执行5次

1.同步方法

同步方法
在这里插入图片描述

2.异步方法

异步方法
在这里插入图片描述

当我们调用同步方法时,程序是按照顺序执行,而下面的异步方法则是无序的,且执行速度也比较快。
在这里插入图片描述

三、多线程的特点

由上我们也可以看出同步和异步多线程方法的特点

  1. 同步方法卡界面,主(UI)线程忙于计算;
  2. 同步线程慢,因为只有一个线程在干活;
  3. 异步多线程方法不卡界面,主线程计算完,计算任务就交给子线程在做;例如winform可以提升用户体验;
  4. 异步多线程方法快,因为多个线程并发运算;
  5. 异步多线程无序:启动无序,执行时间不确定,结束也无序。
  6. 异步多线程并不是线性增长,而是资源换时间,但资源可能不够,其次多线程也有管理成本;
  7. 线程可以加快速度,但不是越多越好

下图可以清楚看到资源换时间的情况;
在这里插入图片描述

四、异步的回调和状态参数

1.顺序控制

从上面的示例中我们使用了异步多线程方式解决了很多问题,但也发现了一个特殊情况,异步是无序的,这时候我们如果想要控制顺序要怎么做呢。这个时候我们就可以使用回调的方式。
首先我们想在计算完成后,在完成后续动作,当我们在BeginInvoke中设置后续两个参数为null,可以看到下图的执行结果,我们的计算明明还没有完成,确提示我们已经完成了,只是主线程完成了。肯定不符合我们的结果。
在这里插入图片描述
在这里插入图片描述
这时候我们把鼠标放到BeginInvoke上可以发现框架已经帮我们提供好了异步回调AsyncCallback
在这里插入图片描述
我们可以看到AysncCallback是一个参数为IAsyncResult类型的委托
在这里插入图片描述
接下来我们修改代码把AsyncCallback传进来
在这里插入图片描述
这时我们再看执行结果,就可以看到我们结果实在最后输出的。
在这里插入图片描述
进行到这里你会想知道这是为什么呢,这个步骤是怎么完成的,callback的参数ia是怎么回事?
在这里插入图片描述
当我们继续把鼠标方法BeginInvake上,我们会发现它其实是一个IAsyncResult类型
在这里插入图片描述
你会发现这不是和上面AsyncCallback的参数ia是一样的吗,接下来我们做个验证

在这里插入图片描述
结果返回True

在这里插入图片描述
这时我们可以理解为,.net框架帮我们做了一个小封装,在执行BeginInvoke的时候会去申请一个线程,线程会先完成委托的调用,执行完成后会产生一个IAsyncResult结果,最后把这个结果作为参数传递给AsyncCallback委托,这也就能解释为什么BeginInvoke结果类型和AsyncCallback的参数类型是一致的。

2.状态参数

接下来我们看BeginInvoke的第三个参数,这时我们随便传入一个“hao”字符串。那么在AsyncState时我们就可以得到,这是为了我们在回调的时候如果想传递某些信息时使用。
在这里插入图片描述

五、异步等待三种方式

1. Thread.sleep等待

这种情况我们可以使用asyncResult.IsCompleted来进行判断委托是否执行完成。在执行完成之后给用户指定提示信息,如下为文件上传操作的示例
在这里插入图片描述
在这里插入图片描述

但是这么写是由弊端的就是会有延迟,也会卡主界面。优点就是我们可以在等待的时候做一些其它操作,例如给用户一些友好提示等。

2.asyncResult.AsyncWaitHandle.WaitOne()

信号量,即时等待

Console.WriteLine("Do Something Else.....");
Console.WriteLine("Do Something Else.....");
Console.WriteLine("Do Something Else.....");
asyncResult.AsyncWaitHandle.WaitOne();//等待任务的完成
  • 1
  • 2
  • 3
  • 4

也可以给asyncResult.AsyncWaitHandle.WaitOne(1000);设置等待时间做超时用,也叫做限时等待。

3.action.EndInvoke()

action.EndInvoke(asyncResult);
EndInvoke可以不仅等待也可以获取返回值,接下来介绍怎么获取返回值。

六、异步返回值

上述我们使用EndInvoke可以不仅等待也可以获取返回值;如下我们可以看到结果正是我们设置的字符串
在这里插入图片描述
在这里插入图片描述
EndInvoke也可以写在回调函数里面,方便我们获取其结果值,但只能写一次,写在里面就不可以写在外面了。
在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/102620?site
推荐阅读
相关标签
  

闽ICP备14008679号