1

EF4.1に問題があります。1つの方法でプロジェクトのパフォーマンスの問題を発見し、問題を解決するためにdotTraceを使い始めましたが、そのような奇妙な動作を発見しました。 ここに画像の説明を入力してください

アプリケーションが起動すると、すべて問題ありません。最初のメソッドの呼び出しは正常に機能しますが、後でMonitor.Enterで費やされる時間は、サイトでいくつかのアクションを実行するたびに長くなります。

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

ありがとうございました。

4

2 に答える 2

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実行中のアクションはスループットにとって実際に問題になる可能性があります。これはバグと見なすことができ、ほとんどの場合スループットを向上させることができる非常に簡単な修正があると思います。

public void PerformAction(TInput input)
{     
    // This is known as Double-Checked Locking  
    if (this._action != null)
    {
        lock (this._lock)
        {
            if (this._action != null)
            { 
                ...
            }
        }
    }
}

トレースの2番目の問題は、同じ問題の後に続きます。

これが本当に問題の原因であることをもう一度確認し(ロックの競合は高負荷の問題であるため、数回の呼び出しでは問題にならないはずです)、MS Connectでバグを開くか、 ADO.NETチームに投稿することをお勧めします。問題の説明としてこの投稿を参照できます。

于 2012-04-19T09:12:03.980 に答える
0

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

すでに述べたように、アプリケーションには奇妙な問題がありました。MVCアプリケーションへのすべての呼び出し、したがってEntityFrameworkへのすべての呼び出しは別々のAppDomainにありました。EF CodeFirstは、AppDomainごとに1回モデルをビルドおよびコンパイルします。私の場合、モデルは毎回ビルドおよびコンパイルされていたため、別のAppDomainでした。原因は単純で、他のチームの誰かが呼び出されたアセンブリにファイルシステムログを追加し、そのアセンブリのクラスを呼び出すたびにファイルが変更され、Webサーバーがアプリケーションを再起動していました。ロギングをオフにしたところ、問題が修正されました。現在、このパフォーマンスの問題はありません。

于 2012-04-21T19:46:58.793 に答える