asp.net MVC アプリで Autofac を使用していますが、ロックに関する問題が発生しました。サービスがシングルトンに依存するときはいつでも、そのサービスはルートの有効期間スコープから解決されます。これは、Autofac が次の理由によるものです。
- ルート スコープからシングルトン コンポーネントを解決します
- ルートから解決する必要がある依存関係を持つルート スコープのコンポーネントを解決します。
さらに、任意のスコープから解決する場合、Autofac はそのスコープをロックします。これらは優れた設計上の決定だと思います。私の問題は、シングルトンに依存し、遅いコンストラクターを持つクラスの誤動作にあります。これらは、シングルトンを解決する必要がある他の人にとってボトルネックになります。
これは MVC アプリ内にあるため、各リクエストは、コンストラクターが挿入された MVC コントローラーにマップされます。さらに、私のコントローラーのほとんどは、さまざまなシングルトン サービス (ロギング、キャッシングなど) に依存しています。
高速なコンストラクターを使用する場合、これは問題ではありません。しかし、適切に記述されていないクラスが 1 つ要求されるとすぐに、その不適切な動作をするコンストラクターですべての新しい要求がブロックされるため、スループットが低下します。例えば:
これら3つのクラスが与えられた
//registered as SingleInstance()
class MySingleton {}
class BadTransient
{
public BadTransient(MySingleton s)
{ Thread.Sleep(5000); }
}
class FriendlyTransient {}
のように解決
using(var scope = container.BeginLifetimeScope("nested scope"))
{
//resolves from child scope
var myFriend = scope.Resolve<FriendlyTransient>();
//resolves from root because it's a singleton
var singleton = scope.Resolve<MySingleton>();
//resolves from root because it has a singleton dependency.
//**** this locks the root scope for 5 seconds
//**** no one else can resolve singletons.
var troublemaker = scope.Resolve<BadTransient>();
}
このボトルネックを回避する方法はありますか?
明白な答えは、高速なコンストラクターを持つことです。現実には、私のコードベースのすべてのコンストラクターが高速であると保証できるわけではありません。レガシーコードがたくさんある、サードパーティのコードに依存しているコードがたくさんある、高速に見えるがそうでないコードに依存しているコードがある、通常は高速だが奇妙な状況で機能しないコードがある、など。ある程度まで。
コンストラクターは見つけ次第修正してきましたが、もっと積極的な解決策が必要です。QA をユーザーに任せることは受け入れられません。
注: シングルトンに依存しない遅いコンストラクターについてはあまり気にしません。ライフタイム スコープはロックされますが、他のスレッドはブロックされません。