首页 > 解决方案 > 将 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上找到

谢谢。

重现步骤

  1. 从: https ://github.com/suchoss/uServiceChasis克隆当前存储库
  2. 从以下位置安装 RabbitMQ:https ://www.rabbitmq.com/#getstarted
  3. 安装 MSSQL
  4. 在 EasyRabbit/startup.cs 中将连接器更改为 DB(第 31 行)
  5. 转到文件夹 RandomNumberPairGenerator 并运行命令 dotnet run 几秒钟,然后您可以使用 ctrl+c 取消它(它会在 RabbitMQ 队列中创建一些消息)
  6. 运行 EasyRabbit 项目并观察每秒处理多少条消息 *. 如果您安装了 RabbitMQ 管理,您可以在http://localhost:15672上查看性能(默认登录名:guest;密码:guest)

编辑:

以下是当前测量的性能:

  1. adder.cs 中的 EF 异步 - 230/s
  2. adder.cs 内没有异步的 EF - 100/s
  3. ADO.NET 异步 - 1300/s
  4. 没有异步的 ADO.NET - 150/s
  5. EF 注入上下文异步 - 40/s
  6. 没有异步的 EF 注入上下文 - 65/s

场景 1.,2.,3.,4。将 adder.cs 作为单例

情景 5.,6。他们将 adder.cs 作为范围服务

标签: c#asp.net-core-2.0ef-core-2.0

解决方案


推荐阅读