.NET 性能改善十大技巧

5a62ff73f9f3a27750f59715e6866b7e.png

概述:今天,我将分享一些加速 .NET Core 应用的简单方法。没有花哨的词语,只有简单的东西。

今天,我将分享一些加速 .NET Core 应用的简单方法。没有花哨的词语,只有简单的东西。

1. 异步编程

.NET Core 中的异步编程是增强应用程序的可伸缩性和响应能力的有效方法。

它允许您的程序在等待操作(如 I/O 进程)完成时处理其他任务。

何时使用异步编程:

  • **I/O 绑定操作:**对涉及数据访问、文件读/写、网络调用等操作使用异步编程,在这些操作中,程序等待外部进程完成。

  • UI 响应能力: 在桌面应用程序中,使用异步在长时间运行的任务期间保持 UI 响应。

  • Web 应用程序中的可伸缩性: 在 Web 应用程序中使用异步,通过在等待数据库查询或 API 调用时释放线程来处理更多请求。

最佳实践:

  • 在库中等待任务时使用,以避免死锁。ConfigureAwait(false)

  • 始终在异步方法中捕获异常,以防止出现未经处理的异常。

  • 编写异步 API 时,如果可能,请将异步方法与同步方法一起公开。

代码示例:

public async Task <ActionResult> GetUserData()  
{  
    var userData = await  _userService.GetUserDataAsync();  
    return View(userData);  
}  
  
public async Task<string> ReadFileContentAsync(string filePath)  
{  
    using (var reader = new StreamReader(filePath))  
    {  
        return await reader.ReadToEndAsync();  
    }  
}

何时不使用异步编程:

  • **CPU 密集型操作:**如果任务涉及密集型计算,异步编程可能不会带来好处,并且会使代码复杂化。

  • 简单的同步任务: 对于快速完成且不阻塞的操作,异步编程可能有点矫枉过正。

常见错误:

  • **阻止异步代码:**避免调用或使用异步方法,因为它可能导致死锁。.Result.Wait()

  • 过度使用 **:**优先使用以获得更好的错误处理和控制。async voidasync Taskasync void

  • 忽略返回的任务: 调用异步方法时,请确保正确处理其任务,方法是 -ing 它或将其作为更大的异步工作流的一部分进行管理。await

2. 优化数据访问

在 .NET Core 中,优化数据访问对于构建高效的应用程序至关重要,尤其是在处理数据库或外部数据源时。

它涉及减少数据库负载、最小化网络流量和加快数据检索的策略。

何时优化数据访问:

  • 大型数据集: 在处理大量数据时进行优化,以减少内存消耗并缩短加载时间。

  • 频繁的数据库交互: 对经常与数据库交互的应用程序应用优化。

  • 性能关键型应用: 对于速度和效率至关重要的应用(如实时数据处理系统)至关重要。

代码示例:

var customers = dbContext.Customers  
                  .Where(c => c.IsActive)  
                  .Select(c => new { c.Name, c.Email })  
                  .ToList();

何时不使用数据访问优化:

  • 小型数据集: 对于小型数据集,对性能的影响可以忽略不计。

  • 简单的 CRUD 操作: 对具有少量记录的单个表的基本操作可能不需要优化。

常见错误:

  • 过度提取数据: 检索的数据过多可能会降低应用程序的速度。

  • N+1 查询问题: 当代码执行一个查询来提取一组记录,然后对每条记录执行其他查询时,就会发生这种情况。

  • 忽略查询执行计划: 不查看查询的执行方式可能会导致错失优化机会。

3.利用缓存

缓存是快速存储和检索数据的有效方法。

在 .NET Core 应用程序中,缓存可以减少重复访问数据库或外部服务等慢速资源的需要,从而显著提高性能。

何时使用缓存:

  • 经常访问的数据: 对经常请求且不经常更改的数据使用缓存。这包括静态配置数据、用户会话信息或经常访问的数据库查询。

  • 读取密集型工作负载: 在应用程序读取数据的频率高于写入或更新数据的频率的情况下,缓存可以大大减少数据源上的负载并加快响应时间。

代码示例:

public class MemoryCacheService  
{  
    private readonly IMemoryCache _memoryCache;  
  
    public MemoryCacheService(IMemoryCache memoryCache)  
    {  
        _memoryCache = memoryCache;  
    }  
  
    public T GetOrCreate<T>(object key, Func<T> createItem)  
    {  
        if (!_memoryCache.TryGetValue(key, out T cacheEntry))  
        {  
            cacheEntry = createItem();  
            _memoryCache.Set(key, cacheEntry);  
        }  
        return cacheEntry;  
    }  
}

在此示例中,方法检查该项是否已在缓存中。如果没有,它将使用提供的函数检索数据并将其添加到缓存中。GetOrCreatecreateItem

何时不使用缓存:

  • 快速变化的数据: 避免缓存频繁更改的数据,因为缓存的主要好处是减少了对不变数据的资源访问。

  • 大型数据集: 缓存非常大的数据集会消耗大量内存资源。请谨慎行事,仅缓存具有性能优势的数据。

常见错误:

  • **过度缓存:**缓存过多的数据可能会导致内存使用量增加和潜在的内存泄漏。只缓存您需要的内容。

  • **忽略缓存过期:**不为缓存项设置过期策略可能会导致提供过时的数据。明智地使用绝对过期策略或滑动过期策略。

  • 不处理缓存未命中: 始终针对在缓存中找不到数据的情况进行编码,并确保可以从原始源检索数据,然后缓存数据以备将来使用。

4. 减少内存分配

在 .NET Core 中,内存分配是指在应用程序运行时为变量和对象保留内存空间的过程。

高效的内存分配对于提高性能至关重要,尤其是在高负载方案中。

何时专注于减少内存分配:

  • 高性能应用: 在性能至关重要的场景中,例如高频交易系统或实时数据处理应用程序。

  • 大规模应用: 在处理大规模应用程序时,小的低效率可能会扩展到大量的资源消耗。

  • 长时间运行的进程: 在长时间运行的应用程序(如 Web 服务器或后台服务)中,以防止内存使用量逐渐增加(内存泄漏)。

减少内存分配的策略:

  1. 在适当的情况下使用值类型: 值类型(如 C# 中的结构)在堆栈上分配,对于小型不可变数据,它可能比引用类型(如类)更有效。

  2. 池化资源: 对常用对象使用对象池,避免重复创建和销毁实例的开销。

  3. 用于字符串连接的 StringBuilder: 在循环或迭代过程中连接字符串时使用。StringBuilder

代码示例:

var builder = new StringBuilder();  
for (int i = 0; i < 100; i++)  
{  
    builder.Append(i);  
}  
string result = builder.ToString();

何时不过度优化:

  • **过早优化:**避免以牺牲代码可读性和可维护性为代价来优化内存分配,尤其是在处理非性能关键型代码路径时。

  • 小型或短期应用: 对于运行时间较短或资源要求较低的应用程序,优化的好处可能无法证明这种努力是合理的。

常见错误:

  • 滥用对象池: 在不需要的地方实现对象池可能会使代码复杂化,而不会带来实质性的好处。

  • **过度使用值类型:**过度使用值类型(尤其是大型结构)可能会导致性能问题,因为值类型是按值复制的,而不是按引用复制的,这可能代价高昂。

  • **忽略垃圾回收器性能:**忽略内存使用模式对垃圾回收器的影响可能会导致性能欠佳。请务必了解垃圾回收在 .NET Core 中的工作原理,以便编写内存高效的代码。

5. 实现高效日志记录

日志记录是任何应用程序监视其行为、诊断问题和了解其性能特征的关键方面。

高效的日志记录在捕获足够的细节和避免过多的数据之间取得平衡,这些数据可能会使系统不堪重负并使日志难以使用。

何时实现日志记录:

  • 错误跟踪: 记录错误和异常以诊断和修复问题。

  • 用户活动监控: 用于跟踪用户操作,尤其是在对安全和审计至关重要的领域。

  • 性能指标: 监视应用程序性能并识别潜在的瓶颈。

  • 调试: 在开发和测试阶段,跟踪代码执行并发现异常。

何时限制日志记录:

  • 高性能方案: 在性能关键型代码路径中,尽量减少日志记录以避免性能下降。

  • 敏感信息: 避免记录敏感信息,例如密码或个人用户数据,以确保安全合规性。

代码示例:

public class MyService  
{  
    private readonly ILogger _logger;  
  
    public MyService(ILogger<MyService> logger)  
    {  
        _logger = logger;  
    }  
  
    public void ProcessData()  
    {  
        try  
        {  
            // Processing logic  
            _logger.LogInformation("Data processed successfully.");  
        }  
        catch (Exception ex)  
        {  
            _logger.LogError(ex, "Error processing data");  
        }  
    }  
}

常见错误:

  • **过度登录:**记录过多的信息可能会导致日志文件过大,从而难以找到相关信息,并可能影响应用程序性能。

  • 不一致的日志记录级别: 如果不使用适当的日志记录级别(例如,Info、Debug、Error),可能会使筛选日志中的相关信息变得具有挑战性。

  • 忽略结构化日志记录: 如果不使用结构化日志记录,可能会使日志数据的自动分析和查询更加困难。

最佳实践:

  • 使用结构化日志记录: 这样可以更轻松地筛选和查询日志数据。例如,使用适用于 .NET Core 的 Serilog 等日志记录框架。

  • 集中日志: 使用 ELK Stack(Elasticsearch、Logstash、Kibana)或 Splunk 等工具集中和分析来自多个来源的日志。

  • 异步日志记录: 请考虑使用异步日志记录,以最大程度地减少对应用程序性能的影响。

6. 使用响应压缩

.NET Core 中的响应压缩是一种用于减小从服务器发送到客户端的 HTTP 响应大小的技术。

通过压缩响应,您可以缩短应用程序的加载时间并减少带宽使用,这对于高流量 Web 应用程序和服务尤其重要。

public void ConfigureServices(IServiceCollection services)  
{  
    services.AddResponseCompression(options =>  
    {  
        options.Providers.Add<GzipCompressionProvider>();  
        options.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(new[] { "application/json" });  
    });  
}  
  
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)  
{  
    app.UseResponseCompression();  
    // other middleware  
}

何时使用响应压缩:

  • 基于文本的内容: 它对基于文本的内容(如 HTML、CSS 和 JavaScript)最有效,这些内容通常可以被大幅压缩。

  • API 响应: 压缩 API 响应,尤其是在返回大型 JSON 或 XML 数据集时。

  • **高流量应用:**在带宽受限或网络性能受限的情况下使用它。

何时不使用响应压缩:

  • **已压缩内容:**避免压缩二进制内容,例如图像或视频,因为它们通常已经被压缩。

  • **响应大小小:**压缩可能对非常小的响应没有好处,因为压缩响应的开销可能超过好处。

  • 敏感数据: 压缩敏感信息时要小心,因为它有时会使数据更容易受到 BREACH 攻击等安全漏洞的影响。

常见错误:

  • **忽略压缩质量设置:**未配置压缩级别。不同的级别可以以 CPU 使用率为代价提供更好的压缩

  • 忽略客户端兼容性: 假设所有客户端都支持相同的压缩算法。确保检查客户端的“Accept-Encoding”标头以应用兼容的压缩格式。

  • 忽略 HTTPS 方案: 虽然响应压缩是有益的,但由于潜在的安全漏洞,在通过 HTTPS 使用时需要仔细考虑。

7. 优化 LINQ 查询

LINQ(语言集成查询)是 .NET Core 中的一项强大功能,它允许开发人员以可读且简洁的方式查询各种数据源。

但是,低效的 LINQ 查询可能会导致性能瓶颈,尤其是在处理大型数据集或复杂操作时。

何时优化 LINQ 查询:

  • **使用大型数据集:**查询大型数据集时,由于内存使用过多或执行时间延长,低效的查询会显著降低应用程序的速度。

  • 数据库操作: 在查询数据库时,尤其是使用 Entity Framework Core 时,请确保对查询进行优化,以防止不必要的数据检索并利用 SQL Server 优化。

  • **性能关键型应用:**在性能是关键的方案中,例如实时数据处理或高负载 Web 应用程序,优化 LINQ 查询至关重要。

何时不过度优化 LINQ 查询:

  • 简单的数据处理: 对于小型内存中集合或简单的数据处理任务,广泛的 LINQ 优化可能不会产生显著的好处。

  • 可读性胜于性能: 有时,更复杂的 LINQ 查询可能更具可读性。如果性能不是主要问题,请优先考虑代码清晰度。

代码示例:

var activeCustomers = dbContext.Customers  
                               .Where(c => c.IsActive)  
                               .Select(c => new { c.Name, c.Email })  
                               .ToList();

此查询仅检索活动客户的必要字段 ( 和 ),从而减少传输和处理的数据量。NameEmail

常见错误:

  • 检索所有数据: 在应用筛选器或转换之前,使用或类似方法从数据库中检索所有记录。.ToList()

  • 循环中的多个查询: 在循环中执行 LINQ 查询可能会导致多个数据库调用,从而极大地影响性能。

  • 忽略延迟执行: 不了解延迟执行可能会导致查询执行效率低下和意外结果。

最佳实践:

  • **首先筛选:**在其他操作之前应用子句以减少处理的数据量。Where

  • 使用投影: 用于仅检索必填字段。Select

  • 避免过早实现: 除非必要,否则不要将查询转换为列表或数组。

  • **了解延迟执行:**在实际需要数据(如调用)之前,不会执行 LINQ 查询,这可以利用它来提高效率。.ToList()

8. 在 API 中使用轻量级对象

在 .NET Core API 中,使用轻型对象(通常称为数据传输对象 (DTO))是优化网络流量和提高 Web 服务性能的最佳做法。

DTO 是简单的序列化对象,用于在应用程序的不同层或部分之间传输数据,尤其是通过网络调用。

何时使用轻量级对象:

  • **客户端和服务器之间的数据传输:**当您需要将数据从服务器发送到客户端时,请使用 DTO,反之亦然,尤其是通过网络。

  • 公开域模型的子集: 当您只需要公开域模型的一部分或将来自各种源的数据聚合到单个对象中时。

  • 性能优化: 在最小化请求和响应有效负载的大小对性能至关重要的情况下。

何时不使用 DTO:

  • 内部应用逻辑: 对于服务器中需要使用完整域模型的内部逻辑,可能不需要 DTO。

  • 简单的 CRUD 操作: 如果您的 API 通过简单的 CRUD(创建、读取、更新、删除)操作紧密镜像您的数据库架构,并且没有安全性或带宽问题,那么直接使用您的域模型可能会更简单。

代码示例:

public class CustomerDto  
{  
    public string Name { get; set; }  
    public string Email { get; set; }  
    // Other relevant data fields  
}  
  
// Mapping domain model to DTO  
public CustomerDto MapToDto(Customer customer)  
{  
    return new CustomerDto  
    {  
        Name = customer.Name,  
        Email = customer.Email  
        // Map other fields  
    };  
}

常见错误:

  • **暴露敏感数据:**在发送到客户端的 DTO 中包括敏感数据。

  • **过度复杂化的 DTO:**使 DTO 过于复杂或包含不必要的数据,从而增加有效负载大小。

  • **忽略 AutoMapper:**不利用像 AutoMapper 这样的对象到对象映射库,导致映射代码冗长且容易出错。

最佳实践:

  • 使用 AutoMapper 进行映射: 使用 AutoMapper 等库来简化域模型和 DTO 之间的映射。

  • 根据用例设计 DTO: 定制 DTO 的结构,以适应特定的用例或 API 端点要求。

  • 验证 DTO: 对 DTO 实施验证,以确保所传输数据的完整性。

9.尽量减少反射的使用

请谨慎使用反射,因为它的计算成本很高。

if (typeof(MyClass).GetMethod("MyMethod") != null)  
{  
    // Method exists logic  
}

频繁使用反射会显著减慢您的应用程序速度。

10. 分析和监视应用程序

定期分析应用程序以识别性能瓶颈。

使用 Visual Studio 诊断工具等工具。

忽视定期性能检查可能会导致未被注意的效率问题。

提高 .NET Core 应用程序的性能不仅仅是编码,而是一种思维方式。

通过采用这 10 大性能技巧,您不仅仅是在编写代码;您正在制作高效、可扩展且强大的应用程序。

如果你喜欢我的文章,请给我一个赞!谢谢

ccae71ef71ff412b99483feeed91b7a3.gif

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值