成都网站seo费用,工程建设的信息网站,typecho客户端wordpress,网站推广引流最快方法前段时间写了一篇关于C#异步编程入门的文章#xff0c;你可以点击《C#异步编程入门看这篇就够了》查看。这篇文章我们来讨论下关于C#异步编程几个不成文的建议#xff0c;希望对你写出高性能的异步编程代码有所帮助。注#xff1a;本文的很多内容都是学习《Effective C#》的… 前段时间写了一篇关于C#异步编程入门的文章你可以点击《C#异步编程入门看这篇就够了》查看。这篇文章我们来讨论下关于C#异步编程几个不成文的建议希望对你写出高性能的异步编程代码有所帮助。注本文的很多内容都是学习《Effective C#》的总结。作者依乐祝原文地址https://www.cnblogs.com/yilezhu/p/12099219.html尽量不要编写返回值类型为void的异步方法在通常情况下建议大家不要编写那种返回值类型为void的异步方法因为这样做会破坏该方法的启动者与方法本身之间的约定这套约定本来可以确保主调方能够捕获到异步方法所发生的异常。正常的异步方法是通过它返回的Task对象来汇报异常的。如果执行过程中发生了异常那么Task对象就进入了faulted故障状态。主调方在对异步方法所返回的Task对象做await操作时该对象若已处在faulted状态系统则会将执行异步方法的过程中所发生的异常抛出反之若Task尚未执行到抛出异常的那个地方则主调方的执行进度会暂停在await语句这里等系统稍后安排某个线程继续执行该语句下方的那些代码时异常才会抛出。总结一句话就是void的异步方法发生异常时开发者得不到任何通知程序既不会触发普通的异常处理程序也不会把这些异常记录下来。总之这会让相关的线程默默的终止掉。不要把同步方法与异步方法组合起来使用用async关键字来修饰的方法意味着该方法有可能会在执行完所有工作之前就把控制权返回给主调方而且它返回给主调方的是个代表工作进度的Task对象。主调方可以查询此对象的状态以了解该工作是否已经完成、尚未完成还是在执行过程中发生了故障。此外这种方法还在暗示主调方本方法所执行的工作可能要花费很长时间因此建议你先去做其他一些事情稍后再来向我索要结果。与此相反如果把某个方法设计成同步方法那么意味着当该方法执行完毕时它的后置条件必定能够得到满足。无论这个方法要花多长时间去完成工作它都会采用与主调方相同的资源来完成主调方必须等这个方法彻底执行完毕才能向下执行。这两种方法单独写起来都很清晰但是如果把他们组合在一起就会让方法变得十分难用而且有可能导致各种bug如死锁。因此这里提出两条重要的原则。第一不要让同步方法必须等待异步方法执行完毕才能往下执行尽量不用Wait()以及.result这些阻塞式的方法。第二不要让异步方法把虽然耗时很长、计算量很大但是完全可以由自己执行的工作转交给另一个异步任务去做。’当然对于第二点这并不是说计算量较大的任务绝对不能放在单独的线程中执行而是说不应该把只用一个线程就能迅速做好的任务刻意的拆解成许多个较小的部分并把他们分别放在多个新的线程上执行而是应该把整个任务都交给某个线程来执行才对。使用异步方法时应尽量避免线程分配异步任务看上去好像很神奇因为这种任务刻意转移到另一个地方去做使得开启这项任务的异步方法可以在该任务完成之后从早前暂停的地方继续往下推进。不过要想发挥异步任务的功效就必须保证把这项任务交出去确实能够少占用一些资源而不是仅仅会在相似的资源之间进行上下文切换。如对于一个控制台程序如果只是执行一项计算量较大且耗时较长的任务或者说运行时间较长的CPU密集型的任务那么把该任务单独放在另一个线程中并没有多大好处。因为这样做只能让工作线程始终处于繁忙状态而主线程则必须一直卡在那里等待工作线程把任务做完。在这种情况下实际上是用两个线程来完成原本只需要一个线程就能做好的工作造成了资源的浪费。避免不必要的上下文切换目前C#代码中使用async以及await实现的异步方法默认是把await之后的代码放在早前捕获的那个上下文中执行的这是因为这样做比较稳妥它最多只会引发几次无谓的上下文切换而不会使程序出现重大的错误与之相反如果系统不把山下文切换回去那么万一遇到的是只能在特定的上下文中才能执行的代码那么程序就有可能崩溃。因此无论有没有必要切换上下文系统都会切换至早前捕获到的那个上下文并把await之后的语句放在那个上下文执行。如果不想让系统做出这样的安排那么可以调用ConfigureAwait()方法。这表示接下来的那些代码无须放在早前捕获的上下文中执行。例如在很多程序集中await语句之后的那些代码一般都与上下文无关因此与可以调用Task对象的ConfigureAwait()方法告诉系统在执行完这项任务之后不必专门把await下面的代码放在早前捕获的上下文中运行。如下所示public static async TaskXElement ReadPacket(string url)
{var resultawait DownloadAsync(url).ConfigureAwait(false);return XElement.Parse(result);
}C#语言默认让程序把await下面的语句都放在早前捕获的上下文中执行这样做虽然较为安全但是会降低程序的效率。因此为了让用户能够更加顺畅的使用程序我们应该调整代码的结构把必须运行在特定上下文的代码剥离出来并尽量考虑在await语句那里调用ConfigureAwait(false)使得程序可以把语句下面的代码放在默认上下文中运行而不是切换回早前的上下文。通过Task对象来进行异步开发Task任务是一种抽象机制可以用来表示某项工作于是就能够把该工作转交给其他资源去完成。Task类型以及与之相关的类与结构体提供了丰富的API让开发者可以操控Task对象以及由该对象所表示的工作。此外Task对象自身也具备一些方法与属性可以用来操作本对象所表示的任务。这些Task对象可以合起来构成一项比较大的任务他们之间既能够按照顺序执行也能够平行的执行。可以通过await语句来确保某些任务之间能够按照一定的顺序执行也就是说只有当该语句所要等待的那项工作完毕之后语句下方的代码才能够执行。总之由于C#提供了一套丰富的API因此可以写出相当优雅的算法来处理Task对象并对这些对象所表示的任务进行安排。对任务的用法理解的越透彻写出来的异步代码越清晰。这里简单说明两个常用的API:WhenAll会根据现有的一批任务创建出一项新的任务只有当那批任务全部执行完毕时这项新人物才能够完成。对Task.WhenAll所返回的新任务进行await操作会获得一份列表早前的那些任务的执行结果就位于该列表中。WhenAny为了尽早的获得某个结果可能启动多项任务使得他们分别从不同的途径去获取该结果。只要其中有一项任务完成你的目标就达成了针对这项需求可以考虑使用Task.WhenAny方法并把自己所创建的那批任务传进去。对WhenAny方法所返回的Task对象进行await操作可以获取到一项任务它指的就是这批任务中最先执行完毕的那项任务。考虑实现任务的取消协议异步任务的编程模型也叫基于任务的异步编程模型提供了标准的API用来取消任务或者广播任务的执行进度。虽然这些API是可选的但如果某项任务确实能够汇报其进度或者能够予以取消那就可以考虑用合适的办法来实现这些API。针对需要取消的任务我们可以通过CanclelationTokenSource对象来进行取消操作。这种对象是一种起到中介作用的对象。该对象处在有可能发出取消请求的客户代码与支持取消功能的那项操作之间。如果正在执行的任务发现客户端想要取消该操作那么它就会通过ThrowIfCanclellationRequested()方法抛出TaskCanclledException异常庸医表示整个工作流程没有能够完全得到执行。此外返回值类型为void类型的异步方法不应该支持取消功能。缓存泛型异步方法的返回值可能你在进行异步编程的时候对异步方法设置的返回类型都是Task或者TaskT然而有些时候把返回值类型设为Task可能会影响性能。如果某个循环或某段代码需要频繁的运行那么系统就有可能分配很多个Task对象从而占用相当多的资源。好在C#提供了一种新的类型叫做ValueTaskT对象他用起来比普通的Task更为高效。该类型是值类型因此创建这种类型的对象时不需要再分配额外的空间。这个好处使得我们可以多创建一些这样的对象而不用担心它会像Task对象那样占据过多的资源。如果你的异步方法可以根据早前缓存起来的结果直接返回相应的值那么尤其应该考虑把返回值类型设置为ValueTaskT。其次ValueTask提供了一个能够接受Task参数的构造函数这个构造函数会在其内部等候该Task的执行结果。总结今天分享的内容比较多而且很多都比较难理解不过确实是写出高性能异步方法所必须要掌握的技巧。由于时间较短因此也没来得及通过代码进行讲述所以需要有一定的基础才能看懂不过还是希望对您有所帮助。好看你就点点我