【问题标题】:Within .NET Core DI, how do singleton lifetime services behave with concurrent requests?在 .NET Core DI 中,单例生命周期服务如何处理并发请求?
【发布时间】:2023-03-11 09:40:02
【问题描述】:

在 .NET Core DI 的上下文中,如果服务注册为 Singleton(生命周期,不要与模式混淆),它是否能够处理多个并发请求?

文档说“每个后续请求都使用相同的实例”。假设我们的数据访问实现是这样注册的。这是否意味着它不会扩展和处理并发请求,并且每个请求基本上都会排队使用该服务?

【问题讨论】:

    标签: .net performance .net-core dependency-injection singleton


    【解决方案1】:

    这是否意味着它不会扩展和处理并发请求,并且每个请求基本上都会排队使用该服务?

    一点也不。当您将服务声明为Singleton(或其他范围)时,您只需 为 DI 定义其生命周期(创建和处置行为)。不多也不少。它对线程的访问方式和服务请求没有任何关系或影响。因此,您必须注意服务的并发问题,并在非线程安全的代码上到处定义锁。

    假设我们的数据访问实现是这样注册的

    特别是如果您使用像实体框架这样的 ORM,您应该知道它的 DbContext 不是线程安全的,并且将其声明为 Singleton 会导致许多并发问题,应该避免。

    【讨论】:

      【解决方案2】:

      根据Microsoft

      Singleton 生命周期服务 (AddSingleton) 在第一次被请求时创建(或者在 Startup.ConfigureServices 运行并使用服务注册指定实例时)。每个后续请求都使用相同的实例。如果应用程序需要单例行为,建议允许服务容器管理服务的生命周期。不要实现单例设计模式并提供用户代码来管理类中对象的生命周期。

      根据上面的说法,你在问题中提到的请求将被排队。

      但如果你从性能的角度考虑,你的替代方案是

      1. 实例化对象
      2. 运行你的方法
      3. 垃圾收集对象

      您不仅在开始时通过实例化对象付出了性能损失,而且在收集它们时还需要 GC 付出更多的努力。

      如果您的单例服务中有一些非常繁重的 CPU 操作,每个请求会使用多次,那么重新考虑您的方法并实现范围生命周期实际上可能是有意义的。

      但是从性能的角度来看,如果可能的话,总体而言创建单例服务仍然是最好的解决方案。

      【讨论】:

      • "您在问题中提到的请求将被排队。"这种说法是不正确的。单例对象不会自动同步(或锁定),因此请求将不会排队。如果需要,应手动实现锁定。
      • @Steven 如果对象被锁定,其余请求的执行将停止,直到对象被实现。这就是我使用问题术语“排队”的意思
      • 如果您使用锁定,这确实会确保执行排队。但这不是单身人士会发生的事情。只有它的初始创建受到某种锁的保护,以保证只创建一个实例。之后,允许任何线程并行调用所有单例的方法。或者 - 至少 - MS.DI DI 容器(或据我所知的任何其他容器)中绝对没有会阻止对单例方法的并行访问。
      猜你喜欢
      • 2020-09-03
      • 2018-12-12
      • 1970-01-01
      • 2021-03-15
      • 2010-10-10
      • 2010-12-06
      • 1970-01-01
      • 1970-01-01
      • 2019-09-11
      相关资源
      最近更新 更多