1

EF 4.1に問題があります。私たちは、一つの方法でプロジェクトにパフォーマンスの問題を発見した私は、この問題を解決するためのドットトレースを使用して開始し、私はそのような奇妙な行動見つけた:アプリケーションが起動すると enter image description hereEntityFramework 4.1 CodeFirst Monitor.Enter

を - すべてがOKである、方法の仕事への最初の呼び出しを私は現場でいくつかのアクションを実行するたびに、Monitor.Enterで費やされる時間が増えます。

私は問題がロックであることを理解しています。何かがコールをブロックすることを意味しますが、何が起こっているのかわかりません。私がEF 4.1のソースを持っていれば、すべてをデバッグしようとすることができましたが、それは私がやる最後のものです。 見たいところを教えてください。そのような動作におそらく何が影響するのでしょうか?私が最初に思ったことはトランザクションですが、少なくとも明示的にこのプロジェクトで使用されたトランザクションは見つかりませんでした。 インターネットで同様の問題が見つからないため、あなたの考えを書くことは大歓迎です。

ありがとうございます。

+0

dbcontextをどのくらい作成していますか?どのデータベースを使用していますか? –

+0

Webリクエストごと、MS SQL 2008 R2 – anderhil

答えて

0

私のコードで問題が見つかりました。それはいつものように、すべてに大きな影響を与えた小さな原因でした。

私がすでに言ったように、アプリケーションには奇妙な問題がありました.MVCアプリケーションを呼び出すたびに、EntityFrameworkが呼び出されるたびにAppDomainが別々になりました。 CodeFirstは、AppDomainごとに一度モデルをビルドしてコンパイルします。私の場合は、毎回モデルをビルドしてコンパイルしていました。別のAppDomainだったからです。原因はシンプルで、他のチームの誰かが呼び出されたアセンブリにファイルシステムのログを追加し、そのアセンブリのクラスを呼び出すたびにファイルが変更され、WebServerがアプリケーションを再起動していました。私はロギングをオフにして、問題を解決しました。今私はこのパフォーマンスの問題はありません。

2

これは非常に興味深い問題です。 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に投稿することをお勧めします。この投稿を問題の説明として参照できます。

+0

ありがとうございました。私はこれが何とか私たちの問題だと思っています。重い負荷がないからです。 dotTraceはメソッドの逆コンパイルされたソースを示していますので、コードはすでに見てきましたが、私たちのコードで何が間違っているのか分かりません。 WebリクエストごとにDbContextを作成していますが、InitializeDatabaseActionが呼び出されるたびに呼び出されます。同じメソッドへの複数の呼び出しで同じDbContextを使用しようとしましたが、これまで行っていません。コンテキストを再利用すると速く実行されます。 – anderhil

+0

さらに調査したところ、私は、DbContextのOnModelCreatingが初めてAppDomainごとに呼び出されたことを覚えているように、MVCアプリケーションが異なるAppDomainsにコントローラを作成していることがわかりました。だから、AppDomainが毎回モデルを作成しようとしていて、お互いに待っているケースがありますか? – anderhil

+0

'Monitor'が単一のAppDomainにスコープされているため、いいえです。とにかく、あなたのMVCアプリケーションが手動でドメインを作成すると、この問題の結果としてさらに多くの問題が生じる可能性があります。 IISでドメインを処理させます。 –

関連する問題