C#异步详解

简介: c#异步编程原理,await asnyc的使用方法

 异步编程是指在程序执行过程中,不需要等待某个操作完成,就可以继续执行后续的代码。比如我们开发了一个web页面中有一个上传文件功能,我们上传文件时使用异步操作,就不用等待文件的上传时间,可以先在网页上进行其他操作。但是如果我们的需求是等待上传文件完成之后才能进行下一步操作,比如我在boss上上传简历,然后根据附件简历生成在线简历,然后我在对在线简历进行优化,这时候就需要加一个await等待这个异步完成。

下面使用代码来举一个例子

创建一个 100000000个a 的超长字符串,然后把这个字符串写进d盘的文本里面

public static async Task Main(string[] args)
{
    string str = new string('a', 100000000);
    await File.WriteAllTextAsync("d:/1.txt", str);//加了await的异步写入
    File.WriteAllTextAsync("d:/2.txt", str);//异步写入
    File.WriteAllText("d:/3.txt", str);
}

image.gif

打个断点 ,一步一步来执行

image.gif

执行完第一行写入到d盘的1.txt时 ,d盘已经有了一个记事本,有很多的a,因为这句代码加了await,这里会等它执行完再到下一步。

image.gif

接着往下走,执行到最后一行代码时,虽然D盘也有2.txt了,但是由于我没有加await,此时并没有等第三句代码执行完。所以这个断点往下走时我们会发现并不会像上面一样等很久,因为异步方法会立刻返回到调用者,因此也叫(非阻塞方法)

image.gif

可以看到记事本中有很多的a,但是很显然没有 100000000个,很显然是写到一半被我的断点停住了。

image.gif

把断点继续,此时最后两句代码一起在执行,分别往2.txt和3.txt写入。

在上面的方法中加入打印线程,看一下执行过程线程的变化

string str = new string('a', 100000000);
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
await File.WriteAllTextAsync("d:/1.txt", str);//加了await的异步写入
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
File.WriteAllTextAsync("d:/2.txt", str);//异步写入
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
File.WriteAllText("d:/3.txt", str);
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);

image.gif

image.gif

打印结果显示,加了await的异步方法执行完后线程发生了变化 ,因为原有线程遇见await会被解放,用于执行异步任务的线程会在任务完成后返回到await处接替原有线程继续执行任务

再举一个例子,我们自己创建一个异步方法

public static  async Task MethodAsync()
{  
    await Task.Run(() =>
    {  
        for (int i = 0; i < 1000; i++)
        {  
            Console.WriteLine(" MethodAsync   "+i);  
        }  
            Console.WriteLine("异步线程=====>"+Thread.CurrentThread.ManagedThreadId);
    });  
}

image.gif

再创建一个普通方法

public static void Method()
    {  
        for (int i = 0; i < 1000; i++)
        {  
            Console.WriteLine(" Method    " +i);  
        }  
            Console.WriteLine("普通方法线程=====>"+Thread.CurrentThread.ManagedThreadId);
    }

image.gif

在main方法中使用await调用异步方法

public static async Task Main(string[] args)
    {
        Console.WriteLine("线程main =====>"+Thread.CurrentThread.ManagedThreadId);
        await MethodAsync();
        Console.WriteLine("线程main=====>"+Thread.CurrentThread.ManagedThreadId);
        Method();
        Console.WriteLine("线程main=====>"+Thread.CurrentThread.ManagedThreadId);
    }

image.gif

把方法停在普通方法前

image.gif

控制台输出👇

image.gifimage.gif

因为加了await,所以等待异步方法for循环完成,从控制台输出结果看出,main方法一开始的线程是1,在执行异步方法时线程是3,执行完异步方法后回到main方法,打印线程还是3,因此上面提到的

原有线程遇见await会被解放,用于执行异步任务的线程会在任务完成后返回到await处接替原有线程继续执行任务

这句话成立。

那我们再试试不加await的

image.gif

还是一样停在刚刚的断点处,可是此时的两次主线程打印都是1,异步方法还没开始打印

image.gif

继续往下走,在控制台中发现,异步方法中新开了一个线程3,和普通方法交叉打印,最后打印主方法的线程也是原来的线程。

image.gif

image.gif

image.gif

说完await,我们再来看看async

async来修饰一个方法,表明这个方法是异步的,声明的方法的返回类型必须为:voidTaskTask<TResult>。方法内部必须含有await修饰的方法,如果方法内部没有await关键字修饰的表达式,哪怕函数被async修饰也只能算作同步方法,执行的时候也是同步执行的。

因此await和async是形影不离的,如下创建两个方法

Task<string> ReadAsync()
    {
        return File.ReadAllTextAsync(@"D:\1.txt");
    }
    async Task<string> ReadAsync2()
    {
        return await File.ReadAllTextAsync(@"D:\1.txt");
    }

image.gif


目录
相关文章
|
4月前
|
编译器 数据处理 C#
C#中的异步流:使用IAsyncEnumerable<T>和await foreach实现异步数据迭代
【1月更文挑战第10天】本文介绍了C#中异步流的概念,并通过使用IAsyncEnumerable<T>接口和await foreach语句,详细阐述了如何异步地迭代数据流。异步流为处理大量数据或需要流式处理数据的场景提供了一种高效且非阻塞性的方法,使得开发者能够更优雅地处理并发和数据流问题。
|
9月前
|
C# 开发者
C# 开发者技术:进程间数据共享之管道(Pipes)-异步通信版
主要类 1.NamedPipeClientStream 2.NamedPipeServerStream 解释:命名管道是一种进程间通信的方式,它允许不同进程之间在同一台机器上进行通信
459 2
C# 开发者技术:进程间数据共享之管道(Pipes)-异步通信版
|
10月前
|
存储 前端开发 API
C# 从做早餐看同步异步
C# 从做早餐看同步异步
41 0
|
11月前
|
存储 SQL 设计模式
C#异步有多少种实现方式?
C#异步有多少种实现方式?
c#异步多线程
c#异步多线程
57 0
|
C#
C#多线程开发-处理异步操作中的异常
C#多线程开发-处理异步操作中的异常
152 0
|
开发框架 Java .NET
C# 同步 异步 回调 状态机 async await Demo
C# 同步 异步 回调 状态机 async await Demo 我们项目的客户端和服务端通信用的是WCF,我就想,能不能用异步的方式调用WCF服务呢?或者说能不能用async await的方式调用WCF服务呢?
543 0
C# 同步 异步 回调 状态机 async await Demo
|
存储 安全 Java
C# 之 异步多线程任务相关以及概念使用介绍
C#异步多线程Task的介绍和使用,从相关关键字到使用示例,详细解析Task和TaskCompletionSource的使用方法。
466 0
C# 之 异步多线程任务相关以及概念使用介绍
|
JSON C# 数据格式
【WPF/C#】联网异步获取二进制文件(如图片)的流程
原文:【WPF/C#】联网异步获取二进制文件(如图片)的流程 步骤: 联网异步获取Json数据。 使用Json.NET工具,反序列化Json为对应的实体类,获得该实体类的对象。 从对象身上获取图片路径(实体类中定义了头像图片是string类型的文件路径)。
1298 0