1

マルチスレッド アプリケーションはスレッドごとに個別のセッションを使用する必要があるという多くの投稿を読みました。ロックがどのように機能するのか理解できないかもしれませんが、すべてのリポジトリ メソッドでセッションをロックすると、単一の静的セッション スレッド セーフにならないのでしょうか?

お気に入り:

public void SaveOrUpdate(T instance)
{
    if (instance == null) return;
    lock (_session)
        using (ITransaction transaction = _session.BeginTransaction())
        {
            lock (instance)
            {
                _session.SaveOrUpdate(instance);
                transaction.Commit();
            }
        }
}

編集:

私が書いているアプリケーションのコンテキスト/タイプを考慮してください:

マルチユーザーではなく、典型的なユーザー インタラクションではありませんが、財務データや注文の更新などのリモート イベントに反応し、それに基づいてタスクを実行し、保存する自律型ロボットです。断続的に、これにより 1 秒あたり最大 10 回の保存のクラスターが作成される可能性があります。通常、毎回保存する必要があるのは同じオブジェクト グラフです。また、起動時に、プログラムは完全なデータベースをエンティティ オブジェクト グラフにロードします。したがって、基本的には一度だけ読み取り、実行時に SaveOrUpdates を実行します。

4

2 に答える 2

4

通常、アプリケーションが同じオブジェクト グラフを編集していることを考えると、これらの編集内容をオブジェクト グラフに適用してデータベースに保存する専用のスレッドを 1 つ用意するか、共通のキューにサービスを提供するスレッドのプールを用意する方が理にかなっています。各スレッドには、ロックする必要のない独自の (専用の) セッションがあります。プロデューサー/コンシューマー キューを検索します (開始するには、こちらを参照してください)。

このようなもの:

[Producer Threads]
Edit Event -\                [Database Servicer Thread]
Edit Event ------> Queue -> Dequeue and Apply to Session -> Database
Edit Event -/ 

BlockingCollection<Action<Session>>そのような実装の良い出発点になると思います。

大まかな例を次に示します (これは明らかにテストされていないことに注意してください)。

// Assuming you have a work queue defined as 
public static BlockingCollection<Action<Session>> myWorkQueue = new BlockingCollection<Action<Session>>();

// and your eventargs looks something like this
public class MyObjectUpdatedEventArgs : EventArgs {
    public MyObject MyObject { get; set; }
}

// And one of your event handlers
public MyObjectWasChangedEventHandler(object sender, MyObjectUpdatedEventArgs e) {
    myWorkQueue.Add(s=>SaveOrUpdate(e.MyObject));
}

// Then a thread in a constant loop processing these items could work:
public void ProcessWorkQueue() {
    var mySession = mySessionFactory.CreateSession();
    while (true) {
        var nextWork = myWorkQueue.Take();
        nextWork(mySession);
    }
}

// And to run the above:
var dbUpdateThread = new Thread(ProcessWorkQueue);
dbUpdateThread.IsBackground = true;
dbUpdateThread.Start();
于 2012-07-25T15:49:47.080 に答える
2

少なくとも 2 つの欠点は次のとおりです。

  1. パフォーマンスを大幅に低下させています。ビジー状態の Web サーバーでこれを実行するのは、映画館の外に群衆がいるのに、人全体の入り口から入場できるようにするようなものです。

  2. セッションには、内部 ID マップ (キャッシュ) があります。アプリケーションごとに 1 つのセッションがあるということは、ユーザーがデータベースのさまざまなデータにアクセスするにつれて、メモリ消費量が増加することを意味します。最終的には、メモリ内にデータベース全体が残ることさえありますが、これはもちろん機能しません。これには、第 1 レベルのキャッシュを時々削除するメソッドを呼び出す必要があります。ただし、キャッシュを削除するタイミングはありません。他の同時セッションがこれに苦しむ可能性があるため、リクエストの最初に立ち寄ることはできません。

人々は他の欠点を追加すると確信しています。

于 2012-07-25T15:35:37.867 に答える