目录

背景

动机和使用案例

Async/Await和返回类型

单元测试异步方法

结论


背景

自.NET 4.5发布以来已经有很长一段时间了。留在了我们的记忆里,其发布在2012年8月15日。是的,六年前。感觉老了吗?好吧,我不打算让你做出改变,而是提醒你一些.NET发布的亮点。此版本带来的主要功能之一是使用async / await方法进行异步编程。基本上,微软的团队通过保持类似于同步代码的逻辑结构,使编译器完成开发人员过去经常做的工作。

你看,在那个时候,Windows Phone仍然是一件事情,为这些平台开发应用程序有一定的局限性。主要原因是Windows Phone与桌面应用程序不同,引入了硬限制,其中任何方法都无法阻塞超过50ms。反过来,这意味着开发人员不再需要阻止UI,这导致了代码中某种异步性的必要性。.NET 4.5展示了对这种必要性的回应。

那么,为什么我要写一些超过五年前发生过的事情呢?好吧,我注意到尽管这是一个古老的话题,仍然有很多工程师都在努力解决这个问题。引用Mike James在iProgrammer中的话:

通常,程序员完全清楚他们正在做的是面向对象的,但只是模糊地意识到他们正在编写异步代码。

这就是为什么我会尝试在一些博客文章中总结这种编程风格中最重要的部分。此外,我们将尝试确定我们应该使用这种编程风格的情况,以及我们应该避免它的情况。所以,让我们潜入它吧!

动机和使用案例

从本质上讲,这种编程风格适用于您需要能够在等待其他事情完成时做某些事情的任何地方。多年来使用这个工具实际上让我们有能力意识到应该在哪里使用它。它非常适合用户体验,通常用于基于事件的系统,例如基于CPU的并行性或使用文件。

任何可能阻止的活动,例如访问Web,都是此方法的良好候选者。如果这些阻止活动中的任何一个在同步过程中结束,则会阻止整个应用程序。另一方面,如果此活动是异步进程的一部分,则应用程序可以继续处理其他任务,直到活动完成。

当然,你不需要滥用这种能力。例如,我们不应异步更新依赖的记录。这通常是一个坏主意,我们的数据将很快失去同步。除此之外,这个概念有时被过度使用。例如,如果我们正在研究一些简单的行动和操作,我们应该考虑更正统的方法。事实上,在这些情况下使用异步概念可能会带来更多的开销而不是收益。

Async/Await和返回类型

异步机制是在我们的代码中使用async / await关键字在.NET中实现的。我们使用async运算符将我们的方法标记为异步。只有具有此运算符方法的方法才能在其中使用 await运算符。  另一方面,await运算符告诉编译器,在等待异步任务完成之前,使用它的异步方法不能继续超过该点(即await标识的语句行)。基本上,它会暂停方法的执行,直到等待完成任务为止。也可以使用其他方法中的await 运算符调用使用async运算符标记的方法。

另一个重要的事情是异步方法必须返回Task类或Task<TResult>类。这是因为在此方法中,await运算符应用于从另一个异步方法返回的  Task。总结一下,异步机制在.NET中实现如下:

  1. 我们使用async运算符来标记我们想要异步的方法。这些方法必须返回Task类或Task<TResult>类。
  2. 当我们调用用async运算符标记的方法时,我们使用await运算符。此运算符将运行异步方法返回的任务。

如何查看代码呢?看看这个示例WebAccess.cs类:

这个类的目标是以非阻塞的方式访问此网站,并获得响应体的长度,为此  AccessRubiksCodeAsync 方法被使用。我们将 Async后缀放在函数名称的末尾,这是异步方法的标准命名约定。AccessRubiksCodeAsync方法正在调用一些同步的操作,就像函数  LogToConsole一样。 重要的是要意识到GetStringAsync方法也是异步的并且它返回Task。 此Tas k稍后由await运算符运行。

注意我们如何获得同步代码的结构,这很棒。即使我们调用await运算符并且在根本上运行了异步任务,我们的代码看起来也非常简洁。这是async / await机制获得大量普及的原因之一。

那么,如果GetStringAsync方法需要很长时间才能应答,会发生什么?以下是工作流如何运行的:

在第一步(标记为1)中,AccessRubiksCodeAsync方法创建HttpClient的实例并调用此类的GetStringAsync方法。目标是以字符串的形式下载网站的内容。如果发生阻塞GetStringAsync 方法的意外事件,例如,该网站下载时间太长,此方法可以控制其调用者(AccessRubiksCodeAsync)。这就是它避免阻塞资源的方式。除此之外,此方法返回Task<int>,AccessRubiksCodeAsync 将其分配给变量getContent。稍后在代码中,此变量与await 运算符结合使用。

现在,由于我们尚未在getContent 上使用await运算符,因此AccessRubiksCodeAsync方法可以继续执行其他操作,而这些操作不依赖getContent任务结果的。因此,LogToConsole 方法可以以同步方式运行(步骤2)。这意味着此方法将采取控制,完成其工作,然后将控制权交还给AccessRubiksCodeAsync方法。

之后,此方法使用await运算符调用getContent(步骤3)。这意味着此时此方法需要GetStringAsync方法的结果。如果此GetStringAsync方法仍未就绪,则AccessRubiksCodeAsync  将暂停其进度并将控制权返回给其调用者。当然,拥有这种流程的好处是我们“给了一些时间”给GetStringAsync方法,同时,我们运行代码的同步部分。下载内容时,结果返回其长度(步骤4)。

单元测试异步方法

单元测试实际上是如何启动async方法的一个很好的例子。在这个例子中,我使用了xUnit,但是async / await 机制有莪支持其他单元测试框架(如NUnit和MSTests)。如果要将xUnit安装到项目中,请在程序包管理器控制台中输入以下命令:

Install-Package xunit
Install-Package xunit.runner.console
Install-Package xunit.runner.visualstudio
Update-Package

好的,这可以让你快速掌握xUnit。现在让我们看一下WebAccess 类的测试类-WebAcces sTests。

现在,让我们分析一下这个测试的重要部分。首先,请注意我们的测试方法如何使用public async Task进行标记,这与标准的public void不同。这是以如下方式完成的:因为在我们的测试方法中,我们实际上是使用await 运算符调用WebAccess类的AccessRubiksCodeAsync方法。我们可以跳过这个方式并在没有await运算符的情况下调用此方法,并保持public void概念,但结果将不是我们预期的。

如果我们这样做会发生什么——在没有await 运算符的情况下调用async方法?那么,在这种情况下,这个异步方法将作为同步方法执行,这意味着它将阻塞线程。同样,这对于UI和Web操作来说是不利的,并且缩放变得不可能。当然,这在某些情况下可以作为优势使用,但重要的是要知道这种机制是如何工作的。

除此之外,测试结构没有重大变化。我们首先在“arrange”阶段创建WebAccess 类的实例  。在“act”阶段,我们使用await运算符来启动AccessRubiksCodeAsync方法并检索结果。最后,在“assert”阶段,我们检查结果的有效性。

结论

异步编程是.NET多年来的一个有点标准的功能。尽管如此,有时我还是觉得经验不足的程序员不太明白这一点。尤其是那些没有其他技术经验的人,这种机制直接用于技术本身,如Node.js. 或者他们熟悉它并尝试在任何情况下使用它。

原文地址:https://rubikscode.net/2018/05/21/asynchronous-programming-in-net-motivation-and-unit-testing/

.NET中的异步编程 - 动机和单元测试相关推荐

  1. .NET中的异步编程——常见的错误和最佳实践

    目录 背景 async void 没有线程 Foreach和属性 始终异步 在这篇文章中,我们将通过使用异步编程的一些最常见的错误来给你们一些参考. 背景 在之前的文章中,我们开始分析.NET世界中的 ...

  2. 一文说通C#中的异步编程补遗

    前文写了关于C#中的异步编程.后台有无数人在讨论,很多人把异步和多线程混了. 文章在这儿:一文说通C#中的异步编程 所以,本文从体系的角度,再写一下这个异步编程.   一.C#中的异步编程演变 1. ...

  3. 一文说通C#中的异步编程

    天天写,不一定就明白. 又及,前两天看了一个关于同步方法中调用异步方法的文章,里面有些概念不太正确,所以整理了这个文章.   一.同步和异步. 先说同步. 同步概念大家都很熟悉.在异步概念出来之前,我 ...

  4. 【转】.Net中的异步编程总结

    一直以来很想梳理下我在开发过程中使用异步编程的心得和体会,但是由于我是APM异步编程模式的死忠,当TAP模式和TPL模式出现的时候我并未真正的去接纳这两种模式,所以导致我一直没有花太多心思去整理这两部 ...

  5. 了解和使用DotNetCore和Blazor中的异步编程

    目录 介绍 您对异步编程了解什么? 那么,什么是异步编程? 我们什么时候应该使用它? 任务.线程.计划.上下文 到底是怎么回事? Asnyc编码模式 命名约定 异步任务模式 任务模式 事件模式 阻塞与 ...

  6. C#中的异步编程(Async)

    文章目录 C#中的异步编程(Async) 前言 示例代码 C#中的异步编程(Async) 前言 所谓的异步,就是指代码在运行的过程中,不会发生阻塞,例如我们玩游戏的时候,游戏在下载资源或者在加载本地资 ...

  7. python异步_Python中的异步编程

    Python部落(python.freelycode.com)组织翻译,禁止转载,欢迎转发. Quora的使命就是分享和增加全世界的知识,并且为了达到这个使命,我们不断地推出改进来让Quora对于我们 ...

  8. .N“.NET研究”ET中的异步编程(二)- 传统的异步编程

    在上一篇文章中,我们从构建响应灵敏的界面以及构建高可伸缩性的服务应用来讨论我们为什么需要异步编程,异步编程能给我们带来哪些好处.那么知道了好处,我们就开始吧,但是在异步编程上海徐汇企业网站制作这个方面 ...

  9. NET中的异步编程(二)- 传统的异步编程

    转自:http://www.cnblogs.com/yuyijq/archive/2011/02/22/1960273.html 在上一篇文章中,我们从构建响应灵敏的界面以及构建高可伸缩性的服务应用来 ...

最新文章

  1. response.getWriter().write()和 response.getWriter().print()的区别
  2. 计算机软件uml,计算机软件——UML旅游管理系统
  3. 解决R 4.0版本包的安装错误
  4. 一步一步搞定InfoPath(02)--配置VSTA
  5. UnicodeDecodeError: 'gbk' codec can't decode byte 0xab in position 43: illegal multibyte sequence
  6. 【WebPack】引入Vue;认识Plugin;使用uglifyjs丑化JS代码;搭建本地服务器;生产开发环境配置文件的抽离
  7. GAN也有脾气:「太难的部分我就不生成了,在下告退」
  8. 解决若依部署出现:Error: Cannot find module ‘xxxx‘
  9. Mac远程服务器文件上传rz和sz的安装使用
  10. 树莓派 4G模块 PPP 拨号 NDIS 拨号
  11. win7中竟然没有telnet.exe??
  12. 【单片机】RGB和RGBW LED灯珠的区别
  13. h5和mysql做图书系统_HTML5的WebGL3D档案馆图书可视化管理系统的实现
  14. doodoo.js快速入门教程 1
  15. “地面哨兵”挑战赛圆满落下帷幕,最终结果揭晓
  16. win10尘埃4点击开始游戏自动关闭没反应|dirt4.exe进程消失的解决方法
  17. 高效发表科技论文的写作方法与技巧
  18. 电动汽车充放电最优调度 研究了EV充电和放电的调度优化问题 我们首先制定全局调度优化问题,其中优化充电功率以最小化所有在白天执行充电和放电的EV的总成本
  19. Python、Cython、CPython的简单对比
  20. 人工智能/机器学习/深度学习:学习路线图

热门文章

  1. linux配置iscsi无账号密码,linux4 如何配置iscsi启动器
  2. 轨道坐标系_天文坐标系分类
  3. prim算法_历时两月,终拿字节跳动offer,算法面试题分享「带答案」
  4. 电商设计师需要的产品广告促销打折标签
  5. UI实用素材|电子商务界面模板
  6. 电商设计师抢着用的液态水滴素材到底有多酷!
  7. 变量命名规则_Java变量与常量
  8. gitclone 一个tag的地址_获取Url地址中参数的几种方法
  9. Java标识符和数据类型
  10. 地震射线追踪与有限差分正演模拟小软件