C#异步详解

举报
爱吃香蕉的阿豪 发表于 2023/11/04 22:29:55 2023/11/04
【摘要】 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);
}

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

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

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

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

 

 把断点继续,此时最后两句代码一起在执行,分别往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);

 打印结果显示,加了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);
    });  
}  

再创建一个普通方法

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

在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);
    }

 把方法停在普通方法前

控制台输出👇

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

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

这句话成立。

 那我们再试试不加await的

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

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

 


 说完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");
    }



【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。