c# - Unity 容器性能优于直接数据访问 - 一个很大的区别

标签 c# performance dependency-injection inversion-of-control ioc-container

我有一个包含大约 30 个项目的解决方案,其中大部分使用 Microsoft Unity 作为容器。

对于此测试,我在不同区域和不同网络中使用远程 Azure SQL 数据库,因此我预计响应会延迟,但这不会影响此测试。

让我们计算使用 Unity 的数据访问时间和使用 DbContext 的直接数据访问时间,这是以毫秒为单位的平均计算:

Unity Container
8749
5757
7225
7072
7256
8791
7016
7465
8449
10741
7852.1 (average)

DbContext
3599
2239
2902
2378
1898
1682
1692
1522
2773
2054
2273.9 (average)

因此,使用 unity 容器访问数据需要 7852.1(平均)毫秒,同时使用 DbContext 访问数据需要 2273.9(平均)毫秒。这是一个很大的性能瓶颈,你不觉得吗?

让我分享一些代码片段,这将展示我如何在项目中使用 Unity。

项目中的 Unity 配置如下所示:

public class UnityConfig
    {
        private static Lazy<IUnityContainer> container = new Lazy<IUnityContainer>(() =>
        {
            var container = new UnityContainer();
            RegisterTypes(container);
            return container;
        });

        public static IUnityContainer GetConfiguredContainer()
        {
            return container.Value;
        }

        public static void RegisterTypes(IUnityContainer container)
        {
            //// Repositories
            container.RegisterType<ICartRepository, CartRepository>();
            // .... total 50 repositories registrations ....

            //// Services
            container.RegisterType<ICartService, CartService>();
            // .... total 72 services registrations ....
        }
    }


public static class UnityWebActivator
{
    public static void Start()
    {
        var container = UnityConfig.GetConfiguredContainer();
        FilterProviders.Providers.Remove(FilterProviders.Providers.OfType<FilterAttributeFilterProvider>().First());
        FilterProviders.Providers.Add(new UnityFilterAttributeFilterProvider(container));
        DependencyResolver.SetResolver(new UnityDependencyResolver(container));

        // TODO: Uncomment if you want to use PerRequestLifetimeManager
        // Microsoft.Web.Infrastructure.DynamicModuleHelper.DynamicModuleUtility.RegisterModule(typeof(UnityPerRequestHttpModule));
    }

    public static void Shutdown()
    {
        var container = UnityConfig.GetConfiguredContainer();
        container.Dispose();
    }
}

这是与 Unity 一起使用的示例存储库和示例服务:

public interface ICartRepository
{
    Cart Get(string id);
    IEnumerable<Cart> GetAll();
    // more codes
}

public class CartRepository : ICartRepository
{
    [Dependency]
    public ApplicationData db { get; set; }

    public Cart Get(string id)
    {
        return db.Carts.AsNoTracking().Where(i => i.Id == id && i.IsDeleted == 0).FirstOrDefault();
    }

    public IEnumerable<Cart> GetAll()
    {
        return db.Carts.AsNoTracking().Where(i => i.IsDeleted == 0);
    }
    // more codes
}

public interface ICartService
{
    Cart Get(string id, string orgid);
    IEnumerable<Cart> GetAll(string orgid);
    // more codes
}

public class CartService : ICartService
{
    private ICartRepository cartRepository;

    public CartService(ICartRepository _cartRepository)
    {
        cartRepository = _cartRepository;
    }

    public Cart Get(string id, string orgid)
    {
        return cartRepository.GetAll().Where(i => i.OrganizationId == orgid && i.Id == id).FirstOrDefault();
    }

    public IEnumerable<Cart> GetAll(string orgid)
    {
        return cartRepository.GetAll().Where(i => i.OrganizationId == orgid);
    }
    // more codes
}

在我使用它们的项目中:

public class HomeController : Controller
{
    private ICartService cartService;

    public HomeController(ICartService _cartService)
    {
        cartService = _cartService;
    }

    public ActionResult Index()
    {
        // through unity
        var item = cartService.Get("id", "org_id");

        // direct DbContext
        ApplicationData data = new ApplicationData();
        var item1 = data.Carts.AsNoTracking().Where(i => i.Id == "id" && i.OrganizationId == "org_id").FirstOrDefault();
        // more code

        return View();
    }
}

这就是我们在应用程序中使用的所有内容。您是否看到可以更改以提高性能的任何内容?

最佳答案

原因是您比较的两种方式完全不同,而不是因为 Unity。第一种方法:

var item = cartService.Get("id", "org_id");

实现为

return cartRepository.GetAll().Where(i => i.OrganizationId == orgid && i.Id == id).FirstOrDefault()

在哪里GetAll是:

public IEnumerable<Cart> GetAll()
{
    return db.Carts.AsNoTracking().Where(i => i.IsDeleted == 0);
}

因为 GetAll返回类型是 IEnumerable<Cart> - cartRepository.GetAll().Where(...)不会过滤掉数据库中的购物车。相反,整个 Cart使用类似 select * from Cart where IsDeleted = 0 的 SQL 查询将表拉入内存.那么Where被执行并找到目标购物车(按组织和 ID)在内存中。当然这是非常低效的(因为它将整个表从您的远程数据库传输到您的机器)并且比另一个 appoach 花费更多的时间,它做:

data.Carts.AsNoTracking().Where(i => i.Id == "id" && i.OrganizationId == "org_id").FirstOrDefault();

这个生成你期望的 SQL,比如 select top 1 * from Cart where IsDeleted = 0 and Id = @id and OrganizationId = @org_id ,所有过滤都发生在数据库中,然后通过网络仅传输一行。

要修复 - 更改您的 GetAll (和其他类似方法)返回 IQueryable :

public IQueryable<Cart> GetAll()
{
    return db.Carts.AsNoTracking().Where(i => i.IsDeleted == 0);
}

关于c# - Unity 容器性能优于直接数据访问 - 一个很大的区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49271181/

相关文章:

c# - Outlook 电子邮件是否有非二进制格式?

php - 提高网站性能的建议 - PHP/MySQL

algorithm - "cycles per byte"对算法的性能意味着什么?

javascript - 工厂没有被注入(inject) Controller - angularJS

node.js - 在 node js 中构建可扩展的 tcp 服务器

c# - 打破 Liskov 替换原则的类使用陷阱

c# - 不保证会调用析构函数

c# - 我们需要 C# 中的定点组合器吗?

c# - Unity.ResolutionFailedException - 依赖项解析失败

sql - 索引字段上的多个过滤器