.NET Core 中实现异步编程并提升性能的操作方法

 更新时间:2024年12月19日 14:52:51   作者:亦世凡华、  
在.net core中异步编程主要通过async和await关键字来实现,结合Task类进行异步操作的管理,这篇文章主要介绍了.NET Core 中实现异步编程并提升性能的操作方法,需要的朋友可以参考下

初识异步编程

异步编程:是指在执行某些任务时程序可以在等待某个操作完成的过程中继续执行其他任务,而不是阻塞当前线程,这在处理I/O密集型操作(如文件读取、数据库查询、网络请求等)时尤为重要,能够显著提高应用程序的性能和响应能力。

在.net core中异步编程主要通过asyncawait关键字来实现,结合Task类进行异步操作的管理:

async:标记方法为异步方法使其能够包含await表达式

await:在异步方法中用于等待一个异步操作完成,允许方法在等待期间继续执行其他代码而不会阻塞线程

异步方法通常返回TaskTask<T> 类型:

Task:表示一个没有返回值的异步操作

Task<T>:表示一个带返回值的异步操作,其中T是返回值的类型

        作用意义:在进行项目开发的时候通常都会遇到异步编程的使用方式,具备的意义如下:

1)提高应用程序响应性:异步编程可以使得应用程序在等待长时间操作(例如网络请求或文件读写)时继续处理其他任务而不会卡住主线程,比如在桌面应用或Web应用中用户界面不会因等待数据加载而变得无响应

2)提升性能:传统的同步编程会阻塞线程直到操作完成,这可能导致线程资源的浪费,特别是在高并发场景下异步编程允许线程释放去处理其他任务,避免了线程饥饿问题,最大化利用CPU资源特别是在I/O密集型操作时

3)节省资源:异步操作不需要为每个操作分配新的线程,因此能够节省系统资源,在高并发情况下异步编程可以显著减少上下文切换开销

4)适用于I/O密集型应用:异步编程特别适用于那些需要大量I/O操作的应用,例如网络请求、磁盘读取、数据库查询等。通过异步操作可以避免长时间等待I/O操作而导致的性能瓶颈

接下来我们通过异步方法从指定的URL路径上下载网页内容,将网页内容保存到本地文件并输出下载的内容的字节数,代码结果如下所示:

using System;
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;
namespace Program
{
    class Program
    {
        static async Task Main(string[] args)
        {
            int len = await DownloadHtmlAsync("https://www.baidu.com", @"d:\test\1.txt");
            Console.WriteLine($"Downloaded {len} bytes.");
        }
        static async Task<int> DownloadHtmlAsync(string url, string filename)
        {
            using (HttpClient client = new HttpClient())
            {
                string html = await client.GetStringAsync(url);
                await File.WriteAllTextAsync(filename, html);
                return html.Length;
            }
        }
    }
}

与多线程关系

异步编程并不等于多线程,这是两个概念,异步方法的代码并不会自动在新线程中执行,除非把代码放到新线程中执行,以下做一个简单的演示:

使用异步方法来执行长时间运行的计算,通过Thread.CurrentThread.ManagedThreadId输出当前执行线程的ID,可以看到异步方法和线程调度的关系如下,这里我们通过计算5000*5000的情况避免执行太快:

using System;
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;
namespace Program
{
    class Program
    {
        static async Task Main(string[] args)
        {
            Console.WriteLine("之前:" + Thread.CurrentThread.ManagedThreadId);
            double r = await CalcAsync(5000);
            Console.WriteLine("之后:" + Thread.CurrentThread.ManagedThreadId);
        }
        static async Task<double> CalcAsync(int n)
        {
            Console.WriteLine("CalcAsync" + Thread.CurrentThread.ManagedThreadId);
            double result = 0;
            Random rand = new Random();
            for (int i = 1; i <= n*n; i++)
            {
                result += rand.NextDouble();
            }
            return result;
        }
    }
}

那么如何在新的线程中执行异步方法呢?这里我们必须手动将异步方法放到新的线程中,这里我们只需要将要执行的代码以委托的形式传递给Task.Run(),这样就会从线程池中取出一个线程来执行我们的委托,如下可以看到我们的线程已经发送了变化:

如果一个异步方法只是对别的异步方法调用转发,并没有太多复杂的逻辑,那么就可以去掉异步关键字直接返回Task,如下所示:

对于多线程来讲,在await调用的等待期间.net会把当前的线程返回给线程池,等异步方法调用执行完毕之后,框架会从线程池再取出一个线程执行后续代码,怎么理解?比如说你进入一家餐馆服务器给你递上一个菜单,在等待你选菜的时候服务你的服务员可能会继续服务别人,当你点餐完毕提交给服务员之后,服务你的服务员可能就不是刚刚服务你的人了,就是这么个意思,当然如果异步等待时间极短,线程可能就不会发送变化:

尽管异步编程和多线程都涉及到并发执行任务,但它们的工作原理和适用场景有所不同,可以把它们看作是两个不同的工具用于解决不同类型的并发问题:

异步编程:通过非阻塞的方式执行操作,适用于 I/O 密集型任务,能够节省线程资源提高应用的响应性。

多线程:通过并行执行任务来提高CPU密集型任务的性能,但线程管理复杂可能带来上下文切换和同步问题。

异步编程与多线程的结合:异步编程通过减少阻塞来提高效率而多线程通过并行执行来加速计算密集型任务,在某些情况下它们可以结合使用:例如异步任务通过线程池线程执行,充分利用多核处理器的计算能力。

异步编程操作

异步等待:如果想在异步方法中暂停一段时间的话,这里可以使用 await Task.Delay()的方式,例如下载一个网址然后等待3秒再下载另一个,注意这里是不能使用Thread.Sleep()方法的,该方法是阻塞线程用的,异步编程并不适用,这里我们演示一下异步等待的效果,如下所示:

class Program
{
    static async Task Main(string[] args)
    {
        var input = Console.ReadLine();
        Console.WriteLine(input);
        await Task.Delay(3000);
        Console.WriteLine(input+".net core");
    }
}

异步取消:在异步编程中CancellationToken是用于取消异步操作的一种机制,它提供了一种优雅的方式来中止正在进行的操作,当用户操作可能会长时间运行时,例如下载文件、访问数据库、调用远程API等,CancellationToken用于支持任务的取消操作,示例如下:

class Program
{
    static async Task Main(string[] args)
    {
        CancellationTokenSource cts = new CancellationTokenSource();
        cts.CancelAfter(3000);
        CancellationToken cToken = cts.Token;
        await Download1Async("https://www.baidu.com", 100, cToken);
    }
    static async Task Download1Async(string url, int n, CancellationToken token)
    {
        using(HttpClient client = new HttpClient())
        {
            for (int i = 0; i < n; i++)
            {
                string html = await new HttpClient().GetStringAsync(url);
                Console.WriteLine($"{DateTime.Now}:{html}");
                if (token.IsCancellationRequested)
                {
                    Console.WriteLine("超时任务取消");
                    break;
                }
            }
        }
    }
} 

当我们打印数据的时候,请求超过5秒还没有结束的话我们就手动取消异步操作:

Task类方法:在Task类中有许多方法可以使用,以下是其常用的方法讲解:

1)Task.WhenAny():任何一个Task完成,Task就完成

2)Task.WhenAll():所有Task完成Task才完成,用于等待多个任务执行结束不在乎顺序

3)Task.FromResult():创建普通数值的Task对象

如下我们可同WhenAll拿到所有文件的数据:

class Program
{
    static async Task Main(string[] args)
    {
        Task<string> t1 = File.ReadAllTextAsync(@"d:\test\1.txt");
        Task<string> t2 = File.ReadAllTextAsync(@"d:\test\2.txt");
        Task<string> t3 = File.ReadAllTextAsync(@"d:\test\3.txt");
        string[] result = await Task.WhenAll(t1, t2, t3);
    } 
} 

到此这篇关于如何在 .NET Core 中轻松实现异步编程并提升性能的文章就介绍到这了,更多相关 .NET Core异步编程内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • aspnet_regiis.exe命令使用方法

    aspnet_regiis.exe命令使用方法

    本文主要介绍各个命令的对应的含义,以及简单说明具体的用法,希望对大家有所帮助。
    2016-05-05
  • Entity Framework之DB First方式详解

    Entity Framework之DB First方式详解

    这篇文章主要为大家详细介绍了Entity Framework三种方式之一DataBase First,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-07-07
  • asp.net用url重写URLReWriter实现任意二级域名 新

    asp.net用url重写URLReWriter实现任意二级域名 新

    最近有个朋友要做url重写的东西,我帮他弄了弄,回头看当年自己写的那个文章,当时以为自己写的很容易理解.但现在再看却觉得写的不好.而今天百度了一下urlrewriter发现我这个文章竟然排第二.为了方便更多朋友,我再写点东西补充下.
    2009-11-11
  • ASP.NET Core中的Http缓存使用

    ASP.NET Core中的Http缓存使用

    这篇文章主要介绍了ASP.NET Core中的Http缓存使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-03-03
  • WPF中常用的布局容器介绍

    WPF中常用的布局容器介绍

    这篇文章介绍了WPF中常用的布局容器,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-04-04
  • 读取XML并绑定至RadioButtonList实现思路及演示动画

    读取XML并绑定至RadioButtonList实现思路及演示动画

    读取XML的文档,可以使用System.Data.DataSet类别中的ReadXml()方法,在aspx网页上拉一个RadioButtonList控件,用来显示XML的数据,接下来,用DataSet去读取刚才写好的获取XML文件的属性,即可完成
    2013-01-01
  • asp.net 将设有过期策略的项添加到缓存中

    asp.net 将设有过期策略的项添加到缓存中

    调用 Insert 方法,将绝对过期时间或弹性过期时间传递给该方法。
    2009-04-04
  • asp.net 多字段模糊查询代码

    asp.net 多字段模糊查询代码

    经常用到多字段的模糊查询,上面的函数可以实现,例如strKeyWords值为“脚本之家”时
    2008-07-07
  • Visual Studio Debug实战教程之基础入门

    Visual Studio Debug实战教程之基础入门

    这篇文章主要给大家介绍了关于Visual Studio Debug实战教程之基础入门的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2018-09-09
  • 三层+存储过程实现分页示例代码

    三层+存储过程实现分页示例代码

    本文为大家介绍下三层+存储过程分页的具体实现,前后台及存储过程代码如下,感兴趣的朋友可以参考下哈
    2013-06-06

最新评论