これは非常に興味深い問題です。 Reflector .NET(ILSpy、JustDecompile、またはDotPeekを使用して、難読化されていない.NETソースコードを参照することもできます)の助けを借りて、素早く簡単に分析しました。分析は間違っているか、間違った前提に基づいている可能性がありますので、考慮してください。
のはInitializeDatabaseAction
から始めましょう:
private void InitializeDatabaseAction(Action<InternalContext> action)
{
Func<Tuple<DbCompiledModel, string>, RetryAction<InternalContext>> valueFactory = null;
if (!this._inDatabaseInitialization)
{
try
{
this._inDatabaseInitialization = true;
if (valueFactory == null)
{
// Delegate to create a new instance of RetryAction
valueFactory = t => new RetryAction<InternalContext>(action);
}
// InitializeDatabases is ConcurrentDictionary - it stores information
// about all compiled models and they related database connection strings
// This call will try to get existing RetryAction for the model and if
// it doesn't exists it will use current valueFactory to create
// a new instance and add it to dictionary. It will also return
// that value and execute its PerformAction operation.
// If you have just one context and one database you will have only
// single record in the concurrent dictionary but every creation
// of your DbContext will go through this call to ensure that database
// is initialized. This code is executed when your context is used
// for data retrieval or persistence for the first time.
InitializedDatabases.GetOrAdd(Tuple.Create<DbCompiledModel, string>(this._model, this._internalConnection.ConnectionKey), valueFactory).PerformAction(this);
}
finally
{
this._inDatabaseInitialization = false;
}
}
}
今度はRetryAction
クラスをチェックしてみましょう:
/// <summary>
/// Adapted from Lazy<> to allow the initializer to take an input object and
/// to do one-time initialization that only has side-effects and doesn't
/// return a value.
/// </summary>
internal class RetryAction<TInput>
{
// Fields
private Action<TInput> _action;
private readonly object _lock;
// Methods
public RetryAction(Action<TInput> action)
{
this._lock = new object();
this._action = action;
}
/// <summary>
/// Performs the action unless it has already been successfully
/// performed before.
/// </summary>
public void PerformAction(TInput input)
{
// Here we have Monitor.Enter
lock (this._lock)
{
if (this._action != null)
{
Action<TInput> action = this._action;
this._action = null;
try
{
action(input);
}
catch (Exception)
{
this._action = action;
throw;
}
}
}
}
}
あなたは多くの並行スレッドを持っている(あなたのASP.NET MVCアプリケーションの負荷が大きい)、あなたがしている場合多くのDbContextインスタンスを作成すると、実際にはスループットに問題が発生する可能性があります。lock
私はこれがバグと見なすことができ、ほとんどの場合スループットを向上させることができる非常に簡単な修正があると信じています:トレースの2番目の問題は同じ問題を抱えています。
私はあなたがもう一度MS Connectに、これは本当にあなたの問題のソース(ロック競合が重い負荷の問題であるので、それはいくつかのコールのために問題になることはありません)とオープンバグであることを検証したりADO.NET teamに投稿することをお勧めします。この投稿を問題の説明として参照できます。
dbcontextをどのくらい作成していますか?どのデータベースを使用していますか? –
Webリクエストごと、MS SQL 2008 R2 – anderhil