VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > 编程开发 > c#编程 >
  • C#中关于异步性能提升——减少线程阻塞

第十部分:性能优化与内存管理
实例99:异步性能提升——减少线程阻塞
实例介绍
之前做电商支付系统时,用户反馈支付接口响应时间超过3秒,通过性能分析发现,接口中同步调用了第三方支付API和数据库查询,导致线程阻塞,系统吞吐量从100QPS降到20QPS。通过异步改造后,接口响应时间降到500ms以内,系统吞吐量提升到500QPS,性能提升25倍。这节就带你从零学习异步性能优化,包括异步编程基础、避免线程阻塞、异步数据库操作、异步HTTP调用,覆盖异vb.net教程C#教程python教程SQL教程access 2010教程步性能提升的核心场景。
需求分析
异步性能提升要解决“线程阻塞、系统吞吐量低、响应时间长”的问题,具体需求如下:
1.线程阻塞避免:识别并避免同步调用导致的线程阻塞;
2.异步编程实现:学习异步编程的基本语法和最佳实践;
3.异步数据库操作:使用EF Core异步API提升数据库操作性能;
4.异步HTTP调用:使用HttpClient异步API提升HTTP调用性能;
5.系统吞吐量提升:通过异步编程提升系统吞吐量,减少资源占用;
代码实现
前置条件:.NET 8 SDK;Visual Studio 2022;SQL Server 2022;
场景1:线程阻塞识别——同步调用导致的性能瓶颈
同步调用第三方API和数据库查询,导致线程阻塞,系统吞吐量低。
步骤1:错误代码(ThreadBlockingExample.cs)
csharp

	using System;
	using System.Data.SqlClient;
	using System.Net.Http;
	using System.Threading.Tasks;
	
	namespace AsyncPerformanceOptimization;
	
	public class PaymentService
	{
	private readonly HttpClient _httpClient;
	private readonly string _connectionString = "Server=.;Database=PaymentDb;Integrated Security=True;TrustServerCertificate=True;";
	
	public PaymentService()
	{
	_httpClient = new HttpClient();
	}
	
	// 错误:同步调用导致线程阻塞,系统吞吐量低
	public string ProcessPayment(PaymentRequest request)
	{
	// 1. 同步查询用户余额(阻塞线程)
	var balance = GetUserBalance(request.UserId);
	if (balance < request.Amount)
	{
	return "余额不足";
	}
	
	// 2. 同步调用第三方支付API(阻塞线程)
	var paymentResult = CallPaymentGateway(request);
	if (!paymentResult.Success)
	{
	return "支付失败:" + paymentResult.Message;
	}
	
	// 3. 同步更新用户余额(阻塞线程)
	UpdateUserBalance(request.UserId, balance - request.Amount);
	
	return "支付成功";
	}
	
	// 同步数据库查询
	private decimal GetUserBalance(int userId)
	{
	using var connection = new SqlConnection(_connectionString);
	connection.Open(); // 阻塞线程,等待数据库响应
	
	using var command = new SqlCommand("SELECT Balance FROM Users WHERE UserId = @UserId", connection);
	command.Parameters.AddWithValue("@UserId", userId);
	
	var result = command.ExecuteScalar(); // 阻塞线程,等待数据库返回结果
	return result != null ? (decimal)result : 0;
	}
	
	// 同步HTTP调用
	private PaymentResult CallPaymentGateway(PaymentRequest request)
	{
	var content = new FormUrlEncodedContent(new[]
	{
	new KeyValuePair<string, string>("OrderId", request.OrderId),
	new KeyValuePair<string, string>("Amount", request.Amount.ToString()),
	new KeyValuePair<string, string>("UserId", request.UserId.ToString())
	});
	
	var response = _httpClient.PostAsync("https://api.paymentgateway.com/pay", content).Result; // 阻塞线程,等待HTTP响应
	response.EnsureSuccessStatusCode();
	
	var responseContent = response.Content.ReadAsStringAsync().Result; // 阻塞线程,等待响应内容
	return Newtonsoft.Json.JsonConvert.DeserializeObject<PaymentResult>(responseContent);
	}
	
	// 同步数据库更新
	private void UpdateUserBalance(int userId, decimal newBalance)
	{
	using var connection = new SqlConnection(_connectionString);
	connection.Open(); // 阻塞线程,等待数据库响应
	
	using var command = new SqlCommand("UPDATE Users SET Balance = @NewBalance WHERE UserId = @UserId", connection);
	command.Parameters.AddWithValue("@NewBalance", newBalance);
	command.Parameters.AddWithValue("@UserId", userId);
	
	command.ExecuteNonQuery(); // 阻塞线程,等待数据库更新完成
	}
	}
	
	public class PaymentRequest
	{
	public string OrderId { get; set; } = string.Empty;
	public int UserId { get; set; }
	public decimal Amount { get; set; }
	}
	
	public class PaymentResult
	{
	public bool Success { get; set; }
	public string Message { get; set; } = string.Empty;
	}

步骤2:性能分析(Visual Studio性能探查器)
1.按F5启动调试,使用性能探查器分析接口性能;
2.查看“线程”选项卡,发现大量线程处于“等待”状态;
3.查看“CPU使用率”,发现CPU使用率只有10%,说明线程被阻塞,CPU资源未充分利用;
场景2:异步改造——避免线程阻塞,提升系统吞吐量
使用异步编程改造同步代码,避免线程阻塞,提升系统吞吐量。
步骤1:修复代码(AsyncPaymentService.cs)
csharp

	using System;
	using System.Data.SqlClient;
	using System.Net.Http;
	using System.Threading.Tasks;
	using Microsoft.EntityFrameworkCore;
	
	namespace AsyncPerformanceOptimization;
	
	public class AsyncPaymentService
	{
	private readonly HttpClient _httpClient;
	private readonly PaymentDbContext _dbContext;
	
	public AsyncPaymentService(HttpClient httpClient, PaymentDbContext dbContext)
	{
	_httpClient = httpClient;
	_dbContext = dbContext;
	}
	
	// 正确:异步方法,避免线程阻塞,提升系统吞吐量
	public async Task<string> ProcessPaymentAsync(PaymentRequest request)
	{
	// 1. 异步查询用户余额(非阻塞线程)
	var balance = await GetUserBalanceAsync(request.UserId);
	if (balance < request.Amount)
	{
	return "余额不足";
	}
	
	// 2. 异步调用第三方支付API(非阻塞线程)
	var paymentResult = await CallPaymentGatewayAsync(request);
	if (!paymentResult.Success)
	{
	return "支付失败:" + paymentResult.Message;
	}
	
	// 3. 异步更新用户余额(非阻塞线程)
	await UpdateUserBalanceAsync(request.UserId, balance - request.Amount);
	
	return "支付成功";
	}
	
	// 异步数据库查询(EF Core异步API)
	private async Task<decimal> GetUserBalanceAsync(int userId)
	{
	// 使用EF Core异步API,非阻塞线程
	var user = await _dbContext.Users
	.FirstOrDefaultAsync(u => u.UserId == userId);
	return user?.Balance ?? 0;
	}
	
	// 异步HTTP调用(HttpClient异步API)
	private async Task<PaymentResult> CallPaymentGatewayAsync(PaymentRequest request)
	{
	var content = new FormUrlEncodedContent(new[]
	{
	new KeyValuePair<string, string>("OrderId", request.OrderId),
	new KeyValuePair<string, string>("Amount", request.Amount.ToString()),
	new KeyValuePair<string, string>("UserId", request.UserId.ToString())
	});
	
	// 使用HttpClient异步API,非阻塞线程
	var response = await _httpClient.PostAsync("https://api.paymentgateway.com/pay", content);
	response.EnsureSuccessStatusCode();
	
	var responseContent = await response.Content.ReadAsStringAsync(); // 异步读取响应内容
	return Newtonsoft.Json.JsonConvert.DeserializeObject<PaymentResult>(responseContent);
	}
	
	// 异步数据库更新(EF Core异步API)
	private async Task UpdateUserBalanceAsync(int userId, decimal newBalance)
	{
	var user = await _dbContext.Users
	.FirstOrDefaultAsync(u => u.UserId == userId);
	if (user != null)
	{
	user.Balance = newBalance;
	await _dbContext.SaveChangesAsync(); // 异步保存更改
	}
	}
	}
	
	public class PaymentDbContext : DbContext
	{
	public DbSet<User> Users { get; set; }
	
	public PaymentDbContext(DbContextOptions<PaymentDbContext> options) : base(options)
	{
	}
	}
	
	public class User
	{
	public int UserId { get; set; }
	public string Username { get; set; } = string.Empty;
	public decimal Balance { get; set; }
	}

步骤2:ASP.NET Core异步接口(PaymentController.cs)
csharp

	using Microsoft.AspNetCore.Mvc;
	using System.Threading.Tasks;
	
	namespace AsyncPerformanceOptimization;
	
	[ApiController]
	[Route("api/[controller]")]
	public class PaymentController : ControllerBase
	{
	private readonly AsyncPaymentService _paymentService;
	
	public PaymentController(AsyncPaymentService paymentService)
	{
	_paymentService = paymentService;
	}
	
	// 异步API接口,非阻塞线程,提升系统吞吐量
	[HttpPost("process")]
	public async Task<IActionResult> ProcessPayment([FromBody] PaymentRequest request)
	{
	var result = await _paymentService.ProcessPaymentAsync(request);
	return Ok(new { Result = result });
	}
	}

场景3:异步编程最佳实践——避免常见陷阱
避免异步编程中的常见陷阱,如异步同步混用、未正确处理异常。
步骤1:错误代码(AsyncPitfallsExample.cs)
csharp

	using System;
	using System.Threading.Tasks;
	
	namespace AsyncPerformanceOptimization;
	
	public class AsyncPitfallsService
	{
	// 错误:异步方法中同步调用.Result或.Wait(),导致线程死锁
	public async Task<string> GetDataAsync()
	{
	// 异步方法
	var dataTask = FetchDataAsync();
	
	// 同步调用.Result,导致线程死锁(在ASP.NET Core中不会死锁,但会阻塞线程)
	var data = dataTask.Result;
	
	return data;
	}
	
	// 错误:异步方法没有使用await,导致编译器警告,方法同步执行
	public async Task<string> FetchDataAsync()
	{
	// 没有使用await,方法同步执行
	return "Data from server";
	}
	
	// 错误:未正确处理异步方法的异常
	public async Task ProcessDataAsync()
	{
	try
	{
	// 异步调用
	await FetchDataAsync();
	}
	catch (Exception ex)
	{
	// 未正确记录异常或处理异常
	Console.WriteLine("Error: " + ex.Message);
	}
	}
	}

步骤2:修复代码(AsyncBestPracticesExample.cs)
csharp

	using System;
	using System.Threading.Tasks;
	using Microsoft.Extensions.Logging;
	
	namespace AsyncPerformanceOptimization;
	
	public class AsyncBestPracticesService
	{
	private readonly ILogger<AsyncBestPracticesService> _logger;
	
	public AsyncBestPracticesService(ILogger<AsyncBestPracticesService> logger)
	{
	_logger = logger;
	}
	
	// 正确:异步方法中使用await,避免线程阻塞
	public async Task<string> GetDataAsync()
	{
	var data = await FetchDataAsync();
	return data;
	}
	
	// 正确:异步方法使用await,编译器无警告
	public async Task<string> FetchDataAsync()
	{
	// 模拟异步操作
	await Task.Delay(100);
	return "Data from server";
	}
	
	// 正确:正确处理异步方法的异常
	public async Task ProcessDataAsync()
	{
	try
	{
	await FetchDataAsync();
	}
	catch (Exception ex)
	{
	// 记录异常,便于排查问题
	_logger.LogError(ex, "Error processing data");
	// 抛出异常或处理异常
	throw;
	}
	}
	}

逐行讲解
场景2:异步改造核心代码
1.async/await关键字:async关键字标记方法为异步方法,await关键字等待异步操作完成,非阻塞线程;
2.Task返回类型:异步方法返回Task或Task,表示异步操作的结果;
3.EF Core异步API:FirstOrDefaultAsync、SaveChangesAsync等异步API,非阻塞线程,提升数据库操作性能;
4.HttpClient异步API:PostAsync、ReadAsStringAsync等异步API,非阻塞线程,提升HTTP调用性能;
场景3:异步最佳实践核心代码
1.避免.Result/.Wait():异步方法中使用await替代.Result或.Wait(),避免线程阻塞和死锁;
2.异步方法必须使用await:异步方法中必须使用await,否则方法会同步执行,编译器会发出警告;
3.异常处理:异步方法的异常可以使用try/catch捕获,和同步方法一样;
基础知识拓展

  1. 异步编程核心概念
    线程阻塞:同步调用会导致线程阻塞,线程在等待操作完成时无法处理其他请求;
    非阻塞线程:异步调用不会阻塞线程,线程在等待操作完成时可以处理其他请求;
    任务调度:异步操作由任务调度器管理,任务调度器会在操作完成时回调继续执行;
    上下文切换:异步编程会减少上下文切换,提升系统性能;
  2. 异步编程最佳实践
实践 原因 好处
async/await全程异步 避免异步同步混用,导致线程阻塞 提升系统吞吐量,减少资源占用
避免.Result/.Wait() 避免线程阻塞和死锁 提升系统稳定性,避免性能瓶颈
使用ConfigureAwait(false) 避免捕获上下文,提升异步操作性能 减少上下文切换,提升执行速度
异步方法命名以Async结尾 符合.NET命名规范,便于识别异步方法 提高代码可读性,避免误用
正确处理异常 异步方法的异常需要正确捕获和处理 提高系统稳定性,便于排查问题
  1. 异步性能对比
    | 指标 | 同步调用 | 异步调用 |
    | ---- | ---- | ---- |
    | 线程阻塞 | 是,线程在等待时无法处理其他请求 | 否,线程在等待时可以处理其他请求 |
    | 系统吞吐量 | 低,线程资源有限 | 高,线程资源可以充分利用 |
    | 响应时间 | 长,多个同步调用串行执行 | 短,多个异步调用并行执行 |
    | 资源占用 | 高,需要更多线程处理请求 | 低,少量线程即可处理大量请求 |

  2. 异步编程适用场景
    IO密集型任务:如数据库操作、HTTP调用、文件读写等,异步编程可以显著提升性能;
    高并发场景:如API接口、微服务、消息队列等,异步编程可以提升系统吞吐量;
    响应式系统:如实时数据处理、WebSocket通信等,异步编程可以提升系统响应速度;

  3. 异步编程常见误区
    异步同步混用:在异步方法中使用.Result或.Wait(),导致线程阻塞;
    过度异步:在CPU密集型任务中使用异步编程,不会提升性能,反而会增加开销;
    未正确处理异常:异步方法的异常未被捕获,导致系统崩溃;
    异步方法未使用await:异步方法中没有使用await,方法同步执行,编译器发出警告;
    总结
    异步性能提升的核心是避免线程阻塞,充分利用线程资源,提升系统吞吐量。关键要点:
    1.异步编程基础:掌握async/await关键字和Task返回类型;
    2.线程阻塞避免:识别并避免同步调用导致的线程阻塞;
    3.异步API使用:使用EF Core异步API和HttpClient异步API提升性能;
    4.最佳实践遵循:遵循异步编程最佳实践,避免常见陷阱;
    5.性能测试:使用性能测试工具(如JMeter、k6)验证异步改造效果;
    比如这个异步性能优化,异步改造后,接口响应时间从3秒降到500ms以内,系统吞吐量从20QPS提升到500QPS,性能提升25倍。掌握异步性能优化,你就能构建高并发、高性能的.NET应用!

 本站原创,转载请注明出处:https://www.xin3721.com/ArticlecSharp/c49497.html


相关教程