C# 中的Async 和 Await 的用法详解
众所周知C#提供Async和Await关键字来实现异步编程。在本文中,我们将共同探讨并介绍什么是Async 和 Await,以及如何在C#中使用Async 和 Await。
同样本文的内容也大多是翻译的,只不过加上了自己的理解进行了相关知识点的补充,如果你认为自己的英文水平还不错,大可直接跳转到文章末尾查看原文链接进行阅读。
作者:依乐祝
原文链接:https://www.cnblogs.com/yilezhu/p/10555849.html
写在前面
自从C# 5.0时代引入async和await关键字后,异步编程就变得流行起来。尤其在现在的.NET Core时代,如果你的代码中没有出现async或者await关键字,都会让人感觉到很奇怪。
想象一下当我们在处理UI和按钮单击时,我们需要运行一个长时间运行的方法,比如读取一个大文件或其他需要很长时间的任务,在这种情况下,整个应用程序必须等待这个长时间运行的任务完成才算完成整个任务。
换句话说,如果同步应用程序中的任何进程被阻塞,则整个应用程序将被阻塞,我们的应用程序将停止响应,直到整个任务完成。
在这种情况下,异步编程将非常有用。通过使用异步编程,应用程序可以继续进行不依赖于整个任务完成的其他工作。
在Async 和 await关键字的帮助下,使得异步编程变得很简单,而且我们将获得传统异步编程的所有好处。
实例讲解
假设我们分别使用了两种方法,即Method 1和Method 2,这两种方法不相互依赖,而Method 1需要很长时间才能完成它的任务。在同步编程中,它将执行第一个Method 1,并等待该方法的完成,然后执行Method 2。因此,这将是一个时间密集型的过程,即使这两种方法并不相互依赖。
我们可以使用简单的多线程编程并行运行所有方法,但是它会阻塞UI并等待完成所有任务。要解决这个问题,我们必须在传统编程中编写很多的代码,但是现在我们有了Async 和 await关键字,那么我们将通过书写很少的并且简洁的代码来解决这个问题。
此外,我们还将看到更多的示例,如果任何第三个方法(如Method 3)都依赖于Method 1,那么它将在Wait关键字的帮助下等待Method 1的完成。
Async 和 await是代码标记,它标记代码位置为任务完成后控件应该恢复的位置。
下面让我们举几个例子来更好进行理解吧
C#中Async 和 await关键字的示例
我们将采用控制台应用程序进行演示。
第一个例子
在这个例子中,我们将采取两个不相互依赖的方法。
class Program
{
static void Main(string[] args)
{
Method1();
Method2();
Console.ReadKey();
}
public static async Task Method1()
{
await Task.Run(() =>
{
for (int i = 0; i < 100; i++)
{
Console.WriteLine(" Method 1");
}
});
}
public static void Method2()
{
for (int i = 0; i < 25; i++)
{
Console.WriteLine(" Method 2");
}
}
}
在上面给出的代码中,Method 1和Method 2不相互依赖,我们是从主方法调用的。
在这里,我们可以清楚地看到,方法1和方法2并不是在等待对方完成。
输出
现在来看第二个例子,假设我们有Method 3,它依赖于Method 1
第二个例子
在本例中,Method 1将总长度作为整数值返回,我们在Method 3中以长度的形式传递一个参数,它来自Method 1。
在这里,在传递Method 3中的参数之前,我们必须使用AWAIT关键字,为此,我们必须使用调用方法中的async 关键字。
在控制台应用程序的Main方法中,因为不能使用async关键字而不能使用await 关键字,因为它会给出下面给出的错误。(但是如果你使用的是C#7.1及以上的方法是不会有问题的,因为C#7.1及以上的语法支持Mian方法前加async)
我们将创建一个新的方法,作为CallMethod,在这个方法中,我们将调用我们的所有方法,分别为Method 1、Method 2和Method 3。
class Program
{
static void Main(string[] args)
{
callMethod();
Console.ReadKey();
}
public static async void callMethod()
{
Task<int> task = Method1();
Method2();
int count = await task;
Method3(count);
}
public static async Task<int> Method1()
{
int count = 0;
await Task.Run(() =>
{
for (int i = 0; i < 100; i++)
{
Console.WriteLine(" Method 1");
count += 1;
}
});
return count;
}
public static void Method2()
{
for (int i = 0; i < 25; i++)
{
Console.WriteLine(" Method 2");
}
}
public static void Method3(int count)
{
Console.WriteLine("Total count is " + count);
}
}
在上面给出的代码中,Method 3需要一个参数,即Method 1的返回类型。在这里,await关键字对于等待Method 1任务的完成起着至关重要的作用。
输出
第三个例子
.NET Framework4.5中有一些支持API,Windows运行时包含支持异步编程的方法。
在Async 和 await关键字的帮助下,我们可以在实时项目中使用所有这些,以便更快地执行任务。
包含异步方法的API有HttpClient, SyndicationClient, StorageFile, StreamWriter, StreamReader, XmlReader, MediaCapture, BitmapEncoder, BitmapDecoder 等。
在本例中,我们将异步读取大型文本文件中的所有字符,并获取所有字符的总长度。
class Program
{
static void Main()
{
Task task = new Task(CallMethod);
task.Start();
task.Wait();
Console.ReadLine();
}
static async void CallMethod()
{
string filePath = "E:\\sampleFile.txt";
Task<int> task = ReadFile(filePath);
Console.WriteLine(" Other Work 1");
Console.WriteLine(" Other Work 2");
Console.WriteLine(" Other Work 3");
int length = await task;
Console.WriteLine(" Total length: " + length);
Console.WriteLine(" After work 1");
Console.WriteLine(" After work 2");
}
static async Task<int> ReadFile(string file)
{
int length = 0;
Console.WriteLine(" File reading is stating");
using (StreamReader reader = new StreamReader(file))
{
// Reads all characters from the current position to the end of the stream asynchronously
// and returns them as one string.
string s = await reader.ReadToEndAsync();
length = s.Length;
}
Console.WriteLine(" File reading is completed");
return length;
}
}
在上面给出的代码中,我们调用ReadFile方法来读取文本文件的内容,并获取文本文件中总字符的长度。
在sampleText.txt中,文件包含了太多的字符,因此读取所有字符需要很长时间。
在这里,我们使用异步编程从文件中读取所有内容,所以它不会等待从这个方法获得一个返回值并执行其他代码行,但是它必须等待下面给出的代码行,因为我们使用的是等待关键字,我们将对下面给出的代码行使用返回值。
int length = await task;
Console.WriteLine(" Total length: " + length);
随后,将按顺序执行其他代码行。
Console.WriteLine(" After work 1");
Console.WriteLine(" After work 2");
输出
最后
在这里,我们必须了解非常重要的一点,如果我们没有使用await 关键字,那么该方法就作为一个同步方法。编译器将向我们显示警告,但不会显示任何错误。
像上面这种简单的方式一样,我们可以在C#代码中使用async 和await关键字来愉快的进行异步编程了。
最后的最后感谢大家的阅读!
本文大部分内容翻译自:https://www.c-sharpcorner.com/article/async-and-await-in-c-sharp/
C# 中的Async 和 Await 的用法详解的更多相关文章
- CSS中伪类及伪元素用法详解
CSS中伪类及伪元素用法详解 伪类的分类及作用: 注:该表引自W3School教程 伪元素的分类及作用: 接下来让博主通过一些生动的实例(之前的作业或小作品)来说明几种常用伪类的用法和效果,其他的 ...
- SVN组成中trunk,branches and tags功能用法详解
SVN组成中trunk,branches and tags功能用法详解 我相信初学开发在SVN作为版本管理时,都估计没可能考虑到如何灵活的运用SVN来管理开发代码的版本,下面我就摘录一篇文章来简单说 ...
- Python中生成器和yield语句的用法详解
Python中生成器和yield语句的用法详解 在开始课程之前,我要求学生们填写一份调查表,这个调查表反映了它们对Python中一些概念的理解情况.一些话题("if/else控制流" ...
- oracle中的exists 和not exists 用法详解
有两个简单例子,以说明 “exists”和“in”的效率问题 1) select * from T1 where exists(select 1 from T2 where T1.a=T2.a) ; ...
- oracle中的exists 和not exists 用法详解(转)
有两个简单例子,以说明 “exists”和“in”的效率问题 1) select * from T1 where exists(select 1 from T2 where T1.a=T2.a) ; ...
- 转:Android中的Handler的机制与用法详解
注:Message类的用法: message的几个参数都可以携带数据,其中arg1与arg2可以携带int类型,what是用户自定义的int型,这样接受者可以了解这个消息的信息. 说明:使用Messa ...
- Python3 中 configparser 模块解析配置的用法详解
configparser 简介 configparser 是 Pyhton 标准库中用来解析配置文件的模块,并且内置方法和字典非常接近.Python2.x 中名为 ConfigParser,3.x 已 ...
- Python3中strip()、lstrip()、rstrip()用法详解
Python中有三个去除头尾字符.空白符的函数,它们依次为: strip: 用来去除头尾字符.空白符(包括\n.\r.\t.' ',即:换行.回车.制表符.空格) lstrip:用来去除开头字符.空白 ...
- SVN中trunk、branches、tags用法详解
Subversion有一个很标准的目录结构,是这样的.比如项目是proj,svn地址为svn://proj/. 那么标准的svn布局是:svn://proj/|+-trunk+-branches+-t ...
随机推荐
- 关于CSS定位属性 position 的使用
CSS中一般通过浮动和定位来对标签进行位置操作.下面我们来讨论一下定位的用法和需要注意的地方. 1.首先,说一下position的几个属性值 (1)none属性值,这个是定义不进行定位,默认为不定位, ...
- Oracle-14:PLSQL
------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- PL/SQL PL/SQL(Procedural Language):过程化sql语言! 在原本的sql语句之 ...
- segmenter_worker.go
package; ; i < engine.initOptions.NumShards; i++ { if i == shard { ...
- timeCache.go
package blog4go import ( "sync" "time" ) const ( // PrefixTimeFormat 时间格式前缀 Pre ...
- Error【0002】:YUM本地源配置问题
1.1 问题背景 通过VMware workstation创建虚拟机,在虚拟机的CDROM设备中,装载操作系统镜像.然后通过mount -o loop的方式,将CDROM设备挂载到系统的/mnt/cd ...
- PHP开发者常用的正则表达式及实例【长期更新收录】
正则表达式在程序开发中是非常有用的,用好正则我们可以搜索.验证及替换文本或任何类型的字符.在这篇文章中,UncleToo为大家搜集了15个开发过程中常用的PHP正则表达式.函数及PHP示例,学习这些你 ...
- spring,springMVC中常用注解
一,使用注解: 在spring的配置文件applicationContext.xml中,加入注解扫描.配置项就配置了对指定的包进行扫描,以实现依赖注入. <?xml version=" ...
- php SESSION入库的实现
session入库,就是重写session制机,在session的周期内,获得到session的数据并记录到数据库 Session默认是存放到服务器上的文件中,不方便管理,如果能把session存放到 ...
- 基于Token认证的多点登录和WebApi保护
在文章中有错误的地方,或是有建议或意见的地方,请大家多多指正,邮箱: linjie.rd@gmail.com 一天张三,李四,王五,赵六去动物园,张三没买票,李四制作了个假票,王五买了票,赵六要直接F ...
- captcha.js一个生成验证码的插件,使用js和canvas生成
一.captcha`captcha.js`是一个生成验证码的插件,使用js和canvas生成的,确保后端服务被暴力攻击,简单判断人机以及系统的安全性,体积小,功能多,支持配置. 验证码插件内容,包含1 ...