c# - 将 EF DatabaseContext 注入自定义 ScopedService
问题描述
在我看来,在作用域服务中注入 EF 的性能真的很低。
在这种情况下,我很有可能错误地使用了 EF,但我无法找到在这种情况下如何使用 EF 的正确描述/文档(将其注入自定义托管服务)。
在 EasyRabbit/startup.cs (ConfigureServices) 中注册了以下服务:
// db
services.AddDbContext<ApplicationDbContext>(options =>
{
options.UseSqlServer("Server=localhost; Database=RabbitTest; MultipleActiveResultSets=true; User ID=sa; Password=Admin1234");
});
// default REST Api
services.AddMvc();
// Configuration for Rabbit connector
services.Configure<RabbitConfig>(Configuration.GetSection("RabbitConfig"));
// Rabbit Connector
services.AddSingleton<RabbitConnector>();
// Subscriber which listens if some new message arrives
services.AddSingleton<IHostedService, GenericHostedSubscriber<CalculatorInputs>>();
// Every arival message is then processed in following scope
// ApplicationDbContext dbContext is injected into this RabbitSubscribers.Adder
services.AddScoped<IScopedProcessingService<CalculatorInputs>, RabbitSubscribers.Adder>();
现在,如果我理解正确,它应该为每个新的 RabbitSubscribers.Adder 范围自动创建 db 上下文范围。
问题是这样它平均每秒只能消耗/处理大约 50 条消息。
当我从以下代码中使用 db(AddAsync 和 SaveChangesAsync)注释所有操作时,它每秒可以处理大约 2000 条消息,这很好但没有 db 对我来说没用:(
namespace EasyRabbit.RabbitSubscribers
{
public class Adder : IScopedProcessingService<CalculatorInputs>
{
private ILogger<Adder> _logger;
private ApplicationDbContext _db;
public Adder(ApplicationDbContext dbContext, ILogger<Adder> logger)
{
_logger = logger;
_db = dbContext;
}
public async Task HandleMessageAsync(CalculatorInputs message)
{
Console.WriteLine($"Calculator: [{message.FirstNumber}] + [{message.SecondNumber}] = {message.FirstNumber + message.SecondNumber}");
await _db.Calculations.AddAsync(new Calculation()
{
FirstNumber = message.FirstNumber,
SecondNumber = message.SecondNumber,
Result = message.FirstNumber + message.SecondNumber
});
await _db.SaveChangesAsync();
}
}
}
当我尝试用 System.Data.SqlClient 替换 EF 时(按照 Adder.cs 中直接使用的一段代码),它平均每秒可以处理 1100 条消息。但是像这样使用数据库真的很不方便:-/
public static class DB
{
private static string _connectionString = "Server=localhost; Database=RabbitTest; MultipleActiveResultSets=true; User ID=sa; Password=Admin1234";
public static void AddRecord(MyDBObject myDBObject)
{
using (SqlConnection con = new SqlConnection(_connectionString))
{
using (SqlCommand cmd = new SqlCommand("insert into test (FirstNumber, SecondNumber, Result) values (@FirstNumber, @SecondNumber, @Result)", con))
{
cmd.CommandType = CommandType.Text;
cmd.Parameters.AddWithValue("@FirstNumber", myDBObject.FirstNumber);
cmd.Parameters.AddWithValue("@SecondNumber", myDBObject.SecondNumber);
cmd.Parameters.AddWithValue("@Result", myDBObject.Result);
con.Open();
cmd.ExecuteNonQuery();
con.Close();
}
}
}
}
public class MyDBObject
{
public int FirstNumber { get; set; }
public int SecondNumber { get; set; }
public int Result { get; set; }
}
整个代码可以在https://github.com/suchoss/uServiceChasis上找到
谢谢。
重现步骤
- 从: https ://github.com/suchoss/uServiceChasis克隆当前存储库
- 从以下位置安装 RabbitMQ:https ://www.rabbitmq.com/#getstarted
- 安装 MSSQL
- 在 EasyRabbit/startup.cs 中将连接器更改为 DB(第 31 行)
- 转到文件夹 RandomNumberPairGenerator 并运行命令 dotnet run 几秒钟,然后您可以使用 ctrl+c 取消它(它会在 RabbitMQ 队列中创建一些消息)
- 运行 EasyRabbit 项目并观察每秒处理多少条消息 *. 如果您安装了 RabbitMQ 管理,您可以在http://localhost:15672上查看性能(默认登录名:guest;密码:guest)
编辑:
以下是当前测量的性能:
- adder.cs 中的 EF 异步 - 230/s
- adder.cs 内没有异步的 EF - 100/s
- ADO.NET 异步 - 1300/s
- 没有异步的 ADO.NET - 150/s
- EF 注入上下文异步 - 40/s
- 没有异步的 EF 注入上下文 - 65/s
场景 1.,2.,3.,4。将 adder.cs 作为单例
情景 5.,6。他们将 adder.cs 作为范围服务
解决方案
推荐阅读
- c++ - C++ lower_bound() 搜索最接近目标值的元素
- stata - 为什么我在 Stata 中的虚拟变量转换会产生:类型不匹配?
- ios - 如何更改 UITableView 中的部分标题文本颜色
- c++ - 如何以“安全”的方式在 C++ 中获取当前时间
- python-3.6 - 我如何打印只有 a_list 中的第一个和最后一个数字以及每个数字之间的“to”的范围?
- caching - C# 我应该将键聚合到更大的对象以进行缓存吗
- continuous-integration - 通过 GitHub Actions 监听 NPM 发布状态的最佳方法
- javascript - 设置最后一位不为零
- google-app-engine - 如何将子域映射到 Google Cloud App Engine 服务并将主域加载静态网站托管在共享主机上?
- flutter - DatePicker + Streams,可以做到吗?