question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Resolving from D.I. is "slow"

See original GitHub issue

Moving this here as a perf issue in D.I. per @divega’s request.

Original issue https://github.com/aspnet/EntityFrameworkCore/issues/12031 filed by @suchoss

Hello, it seems to me that performance of injected EF inside scoped service is really low.

There is a high chance that I am using EF incorrectly in this case, but I have not been able to find proper description/documentation how to use EF in this case (Inject it into custom hosted service).

In EasyRabbit/startup.cs (ConfigureServices) are registered following services:

// 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>();

Now if I understand it correctly, it should automatically create db context scope for every new RabbitSubscribers.Adder scope.

Problem is that like this it can consume/process only about 50 messages per second on average.

When I comment all operations with db (AddAsync and SaveChangesAsync) from following code, then it can process about 2000 messages per second which is nice but without db useless for me 😦

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();
            
        }
    }
}

When I tried to replace EF with System.Data.SqlClient (following piece of code directly used in Adder.cs), then it could process 1100 messages per second on average. But to work with DB like this is really unconvinient 😕

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; }
}

Thanks.

Steps to reproduce

  1. Clone current repository from: https://github.com/suchoss/uServiceChasis
  2. Install RabbitMQ from: https://www.rabbitmq.com/#getstarted
  3. Install MSSQL
  4. Change connector to DB in EasyRabbit/startup.cs (line 31)
  5. Go to folder RandomNumberPairGenerator and run command dotnet run for a few seconds, then you can cancel it with ctrl+c (it creates some messages into RabbitMQ queue)
  6. Run EasyRabbit project and watch how many messages per second is being processed *. If you have RabbitMQ management installed you can watch performance on http://localhost:15672 (default login: guest; password: guest)

Further technical details

EF Core version: EF Core 2.0.2 Database Provider: Microsoft.EntityFrameworkCore.SqlServer Operating system: Win 10 IDE: Visual Studio 2017 15.7.1

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Comments:16 (12 by maintainers)

github_iconTop GitHub Comments

2reactions
ajcvickerscommented, Aug 6, 2018

Comment by @suchoss

Hello @ajcvickers,

So today, I’ve created following three projects:

  1. DependencyInjection - EF DbContext (ModelContext) is injected into controller through ctor
  2. DirectAproach - EF DbContext is created direcly in controller with using block
  3. MeasureApp - app which measures performance of both solutions

Steps to reproduce:

  1. Download zip file from attachment
  2. Install MSSQL server on localhost so you can connect with following connection string: "Server=localhost; Database=DIApproach; MultipleActiveResultSets=true; User ID=sa; Password=Admin1234" or change connection string accordingly in Startup.cs (DependencyInjection project) and in ModelContext.cs (DirectAproach project)
  3. Run following command in DependencyInjection and DirectAproach project folders: dotnet ef database update
  4. In both folders from step 3. run this command dotnet run
  5. Wait until both apps start.
  6. Go to the folder MeasureApp and run command dotnet run
  7. Be patient - on my laptop it takes about 2 minutes until test ends.

Conclusion:

If you are successful with running test you should see following results - of course that on different hw those times are going to be different - (measured 10x): Time: 00:00:51.5376170, url: http://localhost:5000/api/DI Time: 00:00:46.4245608, url: http://localhost:5001/api/Direct Time: 00:00:50.6788257, url: http://localhost:5000/api/DI Time: 00:00:46.3511890, url: http://localhost:5001/api/Direct Time: 00:00:52.3130819, url: http://localhost:5000/api/DI Time: 00:00:47.1922426, url: http://localhost:5001/api/Direct Time: 00:00:52.1807489, url: http://localhost:5000/api/DI Time: 00:00:46.9598238, url: http://localhost:5001/api/Direct Time: 00:00:50.8818136, url: http://localhost:5000/api/DI Time: 00:00:45.2605405, url: http://localhost:5001/api/Direct Time: 00:00:50.7522685, url: http://localhost:5000/api/DI Time: 00:00:46.5828745, url: http://localhost:5001/api/Direct Time: 00:00:51.2286150, url: http://localhost:5000/api/DI Time: 00:00:47.3935218, url: http://localhost:5001/api/Direct Time: 00:00:51.2117850, url: http://localhost:5000/api/DI Time: 00:00:46.2748000, url: http://localhost:5001/api/Direct Time: 00:00:51.4667565, url: http://localhost:5000/api/DI Time: 00:00:45.4717610, url: http://localhost:5001/api/Direct Time: 00:00:50.6048048, url: http://localhost:5000/api/DI Time: 00:00:46.0667616, url: http://localhost:5001/api/Direct

From those numbers you can see that injected EF db context is on average about 9 % slower.

This behaviour is getting even worse when used as described in my first post, but now I also noticed that it was maybe caused by “busy” hard drive (because of RabbitMQ). I’ll try to verify that on some server machine (maybe next week), but meantime you can test scenario from this test if that reproduces even on your computers. EFCoreIssue.zip

1reaction
divegacommented, Jan 9, 2019

@muratg I had no specific expectations on this.

The 9% difference mentioned at https://github.com/aspnet/Extensions/issues/691#issuecomment-410825384 just made me wonder if there was a perf issue in DI worth looking at.

@pakrym’s analysis indicates that the difference when you look at DI vs constructor in isolation is minimal. It seems ok to then conclude that it is not because of a perf issue in DI.

However, I don’t think we have been able to explain why the difference becomes more noticeable when there are other components interacting. Not to mention the more significant differences mentioned in https://github.com/aspnet/Extensions/issues/691#issuecomment-410824355:

  1. EF async inside adder.cs - 230/s
  2. EF without async inside adder.cs - 100/s
  3. ADO.NET async - 1300/s
  4. ADO.NET without async - 150/s
  5. EF injected context async - 40/s
  6. EF injected context without async - 65/s

Of course, any differences between ADO.NET and EF Core are not likely attributable to DI.

Read more comments on GitHub >

github_iconTop Results From Across the Web

5 Methods to Fix Slow Playback in DaVinci Resolve 16
In this DaVinci Resolve 16 Tutorial, we'll be looking at how you can fix slow playback issues in DaVinci Resolve 16 and poor...
Read more >
Resolve extremely slow after disk change : r/davinciresolve
It's possible something got messed up when it moved. But if Resolve is storing the database on the exFAT drive, this could slow...
Read more >
Troubleshooting slow dependency resolving
Hey folks, I'm seeing pathologically slow build speeds with certain JDK versions, whereas other versions are blazing fast.
Read more >
domain name system - Resolving host is consistently slow
On another machine it takes exactly 30 seconds. Both Linux. My code is in Java but the problem is reproducable using wget: time...
Read more >
Slow Resolve Speed
The issue is that Control D has very few servers near your location. The farther the DNS server, the slower the resolve speed....
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found