同步异步和单线程多线程有什么联系_线程异步和同步的区别

同步异步和单线程多线程有什么联系_线程异步和同步的区别C#之多线程和异步编程1.进程、线程计算机的概念进程:一个程序运行时,占用的全部计算资源的总和线程:线程本质上不是一个计算机的硬件功能,而是操作系统提供的一种逻辑功能 程序执行流的最小单位任何操作都是有线程完成的线程是依

C#之多线程和异步编程   1.进程、线程计算机的概念进程:一个程序运行时,占用的全部计算资源的总和线程:线程本质上不是一个计算机的硬件功能,而是操作系统提供的一种逻辑功能 程序执行流的最小单位任何操作都是有线程完成的线程是依托于进程存在的,一个进程可以包含多个线程线程也可以有自己的计算资源多线程:多个执行流同时运行CPU太快了,分时间片:上下文进行切换(加载环境–计算–保存环境);微观角度,一个核同一时刻只能执行一个线程;宏观角度,多线程并发多CPU多核,可以独立工作;4核8线程–核是物理的核,线程是指虚拟核   2.同步和异步同步:完成计算之后,再进入下一行异步:不会等待方法的完成,会直接进入下一行(非阻塞)   3.异步和多线程的联系和区别相同点异步和多线程两者都可以达到避免调用线程使程序发生阻塞的目的,来提高软件的响应性和流畅度区别多线程是多个Thread并发,需要开辟新的线程异步是硬件式的异步,没有开辟新的线程,简单来说就是当CPU发送完操作命令后,就不再等着命令的执行结束,而是可以去执行别的任务,当上述任务结束时,会触发一个回调,告诉CPU任务执行完毕了,可以接着执行了异步更强调等待完成,多线程更强调并行异步方法通常使用回调来进行处理   4.异步多线程无序启动无序,执行时间不确定,结束也无序,一定不要通过等几毫秒的形式来控制启动/执行时间/结束可以通过回调/状态等待/信号量来进行控制   5.前台线程和后台线程默认情况下,手动创建的线程属于前台线程只要有前台线程在运行,那么应用程序就会一直处于活跃状态只要后台线程则应用程序不会处于活跃状态,一旦所有的前台线程停止,那么应用程序就停止了,任何的后台线程也会突然终止C#中可以通过IsBackground属性判断线程是否属于后台线程,若程序的前台线程全部执行完后,则后台线程执行栈中的finally块也就不会被执行了注意:线程的前台、后台状态与它的优先级无关(所分配的执行时间);若应用程序无法正常退出,则有一个常见的原因是还有活跃的前台线程   6.线程安全状态的保存:Local本地状态,CLR为每一个线程分配自己的内存栈(Stack),使本地变量保持独立如果多个线程引用到同一个对象的实例,则就共享了数据被Lambda表达式或匿名委托所捕获的本地变量,会被编译器转化为字段(field),也会被共享静态字段(field)也会在线程间共享数据。此时会存在线程安全的问题在读取和写入共享数据的时候,通过使用一个互斥锁(exclusive lock),可以避免同时修改共享数据C#使用lock语句来加锁当两个线程同时竞争一个锁的时候(锁可以基于任何引用类型对象),一个线程会等待或阻塞,直到锁变成可用状态在多线程上下文中,以这种方式避免不确定的代码来使得线程安全注意:Lock也会引起一些问题,例如死锁异常处理创建线程时在作用范围内的try/catch/finally块,在线程开始执行后就与线程无关了,需要将捕获放置在线程所执行的代码块中在WPF、WinForm里,可以订阅全局异常处理事件:Application.DispatcherUnhandledExceptionApplication.ThreadException在通过消息循环调用的程序任何部分发生未处理的异常(相当于应用程序处于活跃状态时在主线程上运行的所有代码)后,将触发这些异常但是在非UI线程上的未处理异常,并不会触发它任何线程有任何未处理的异常都会触发的事件:AppDomain.CurrentDomain.UnhandledException富客户端应用通常依赖于集中的异常处理事件来处理UI线程上未捕获的异常WPF中的Application.DispatcherUnhandledExceptionhttp://ASP.NET Core中定制的ExceptionFilterAttribute也是相同的效果   7.线程优先级线程的优先级(Thread的Priority属性)决定了相对于操作系统中其它活跃线程所占的执行时间提升线程优先级:提升线程优先级的时候需要特别注意,因为它可能“饿死”其它线程如果想让某线程的优先级比其它进程中的线程优先级高,那就必须提升线程的优先级对于需要大量计算的应用程序(尤其是有UI的应用程序),提高线程优先级可能会使其他线程“饿死”,从而降低整个计算机的速度   8.信号如果需要让某个线程一直处于等待的状态,直至接收到其它线程发来的通知(信号)最简单的信号结构就是ManualResetEvent调用其WaitOne方法会阻塞当前的线程,直到另一个线程通过调用set方法来开启信号调用完Set之后,信号就会处于“打开”的状态,并且可以通过调用Reset方法将其再次关闭   9.客户端应用程序中的线程在WPF,WinForm,UWP等类型的程序,如果在主线程执行非常耗时的操作,就会导致整个应用程序无响应(假死)。其主线程在处理计算任务的同时,还需要处理消息循环(渲染,鼠标键盘事件等工作)针对耗时的操作,主要流行的做法是启用一个worker线程,执行完计算任务后,再更新到UI客户端应用的的线程模型通常是:UI素和控件只能从创建它们的线程来访问(通常是主UI线程)如果需要从worker线程更新UI,则必须把请求交给UI线程,实现方式包括:WPF,在素的Dispatcher对象上调用BeginInvoke或InvokeWinForm,调用空间的BeginInvoke或InvokeUWP,调用Dispatcher对象上的RunAsync或InvokeBeginInvoke和RunAsync通过将委托排队到UI线程的消息队列来执行工作Invoke执行相同的操作,但随后会进行阻塞,直到UI线程读取并处理消息Invoke可以从方法中返回值如果不需要返回值,则BeginInvoke和RunAsync更好,不会阻塞UI,也不会引入死锁的可能性同步上下文(Synchronization Contexts)在System.ComponentModel下有一个抽象类:SynchronizationContext,它使得Thread Marshaling得到泛化针对移动,桌面(WPF、UWP、WinForms)等富客户端应用的API,它们都定义和实例化了SynchronizationContext的子类可以通过静态属性 SynchronizationContext.Current来获得(当运行在UI线程时)捕获Post就相当于调用Dispatcher或Control上面的BeginInvoke方法,而send方法,等价于Invoke方法   10.线程池当开始一个线程的时候,将花费几百微秒来组织类似以下的内容:一个新的局部变量栈(Stack)线程池就可以节约上述这种开销:通过预先创建一个可循环使用的线程池线程池对于高效的并行编程和细粒度并发是极为重要的线程池允许在不被线程启动的开销淹没的情况下运行短期操作使用线程池需要注意的:不可以设置线程池的Name线程池线程都是后台线程阻塞线程池线程可能会使性能降级可以更改线程池线程的优先级,但是当它释放回线程池的时候,其优先级将还原可以通过Thread.CurrentThread.IsThreadPoolThread属性来判断是否执行在线程池上以下内容使用了线程池:WCF,Remoting,ASP.NET,ASMX Web Services应用服务器System.Timers.Timer,System.Threading.Timer并行编程结构BackgroundWorker类异步委托最简单的、显示的在线程池上运行代码的方式为使用Task.Run   11.异步编程之Task类 异步编程的原则是将长时间运行的函数写成异步。在传统的做法中是将长时间运行的函数写成同步,然后从新的线程或Task中进行调用,按需进行并发,而异步编程是从长时间运行函数的内部启动并发,其优势是:计算并发可不使用线程来实现,从而提高可扩展性和执行效率;可以减少富客户端的worker线程的代码,从而简化了线程安全性。 Task是一个相对高级的抽象:其代表一个并发操作(concurrent)。该操作可能由Thread支持,或者不由Thread支持。Task是可以组合的(可使用Continuation把它们连接起来) Task可以使用线程池来减少启动延迟;使用TaskCompletionSource,Task可以利用回调的方式,在等待I/O绑定操作时完全避免线程。Task默认使用线程池,也就是后台线程:当主线程结束时,你创建的所有tasks都会结束Task.Run会返回一个Task对象,可以使用它来监控其过程调用task的wait方法会进行阻塞直到操作完成在线程池中运行的Task,非常适合短时间运行的计算类工作针对长时间运行的任务或阻塞操作,可以不采用线程池Task的返回值Task有一个泛型的子类Task,其会发出一个返回值使用Func委托或兼容的Lambda表达式来调用Task.Run就可以得到Task如果task没有完成,则访问Result属性会阻塞该线程直到task完成操作Task异常task里面抛出了一个未处理的异常,那么该异常就会重新被抛给:调用了wait()的地方访问Task的Result属性的地方如果没有抛出异常,通过Task的IsFaulted和IsCanceled属性也可以检测出Task是否发生了故障如果两个属性都返回false,那么没有错误发生如果IsCanceled为true,那么就说明一个OperationCanceledexception被Task抛出如果IsFaulted为true,那么就说明另一个类型的异常被抛出,其Exception属性也将指明该错误Task的链式调用(Continuation、ContinueWith)Continuation通常是通过回调的方式来实现,当操作一结束,就开始执行在Task上调用GetAwaiter会返回一个awaiter对象可以将Continuation附加到已经结束的task上面,则此时Continuation将会立即被执行如果任务发生异常,则在Continuation中调用awaiter.GetResult()时,异常会重新被抛出调用awaiter.GetResult()(没有返回值同样)相比Result属性的好处是,如果task发生故障,则异常会直接被抛出如果出现同步上下文,则Continuation会重新回到UI线程中(没有则会继续运行在task线程上),假如不希望回到UI线程中,则可以通过ConfigureAwait方法来避免,此时还是会回到task线程上其另一种附加Continuation的方式就是调用task的ContinueWith方法ContinueWith本身返回一个task,可以用来附加更多的ContinuatioTask的另一种执行异步方法的方式为使用TaskCompletionSource来创建TaskTaskCompletionSource可以在任意操作中指定开始提供一个“从属”的Task来指示操作何时结束或发生故障   async和await关键字可以按照写同步代码的方式来构建简洁且结构相同的异步代码await关键字简化了附加的Continuation过程async修饰符会让编译器把await当作关键字而不是标识符(c#5以前可能会使用await作为标识符)async修饰符只能应用于方法(包括lambda表达式)该方法可以返回void、Task、Taskasync修饰符对方法的签名或public数据没有影响(和unsafe一样),它只会影响方法的内部在接口内使用async是没有意义的使用async来重载非async的方法是合法的(只要方法的签名一致)使用了async修饰符的方法就是“异步函数”在异步方法内,await表达式可以替换任何表达式,除了lock表达式和unsafe上下文await表达式之后在以下线程上执行:await之后,编译器依赖于Continuation来继续执行如果在富客户端应用的UI线程上,同步上下文会保证后续是在原线程上执行否则,就会在task结束的线程上继续执行匿名方法(包括Lambda表达式),通过使用async也可以变成异步方法,调用方式也一样附加的event handler的时候也可以使用异步Lambda表达式对于在循环中多次调用的异步方法,通过调用ConfigureAwait方法,可以避免重复弹回到UI消息循环中所带来的开销   对于异步方法,可以利用CancellationToken来取消异步操作在异步方法中可以使用IProgress和Progress来报告完成的进度Task组合器Task.WhenAny,当一组Task中的任何一个Task完成时,Task.WhenAny就会返回完成的Task。如果当一组Task中已经完成某一个任务,则没完成的Task在后续中发生异常,则异常不会被检测到,除非对后续的所有Task进行awwitTask.WhenAll,当一组Task中的所有Task都完成时,Task.WhenAll就会返回完成的Task。与WhenAny不同的是,如果一组Task中的某一个Task出现异常,则无需等待后续的Task,其错误也会被检测到

2024最新激活全家桶教程,稳定运行到2099年,请移步至置顶文章:https://sigusoft.com/99576.html

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。 文章由激活谷谷主-小谷整理,转载请注明出处:https://sigusoft.com/38063.html

(0)
上一篇 2024年 9月 8日 下午8:53
下一篇 2024年 9月 8日 下午9:02

相关推荐

关注微信