3

Web アプリケーションで潜在的な競合状態に直面しています。

# get the submissions so far from the cache
submissions = cache.get('user_data')
# add the data from this user to the local dict
submissions[user_id] = submission

# update the cached dict on server
submissions = cache.update('user_data', submissions)

if len(submissions) == some_number:
    ...

ロジックは単純です。まず、Web サーバーのキャッシュに保存されている共有辞書をフェッチし、送信 (サーバーへの各要求によって配信される) をそのローカル コピーに追加します。次に、キャッシュされたコピーをこの更新されたローカルに置き換えることで更新します。コピー。最後に、特定の数のデータを受け取った場合は、別のことを行います。注意してください

submissions = cache.update('user_data', submissions)

キャッシュからディクショナリの最新のコピー、つまり新しく更新されたものを返します。

サーバーは複数の要求を (それぞれ独自のスレッドで) 同時に処理する可能性があり、これらすべてのスレッドが前述のようにキャッシュ内の共有ディクショナリにアクセスするため、競合状態が発生する可能性があります。

Web プログラミングのコンテキストでは、パフォーマンスをあまり犠牲にすることなく、この特定のケースで競合状態を防ぐためにスレッドを効率的に処理するにはどうすればよいのでしょうか。いくつかのコード例をいただければ幸いです。

4

3 に答える 3

2

私の好ましい解決策は、送信辞書を変更する単一のスレッドと、そのスレッドにフィードするキューを持つことです。あなたが偏執狂的である場合は、送信辞書で読み取り専用ビューを公開することもできます. キューとコンシューマ パターンを使用すると、ロックの問題は発生しません。

もちろん、これは、そのスレッドを作成できる Web フレームワークがあることを前提としています。

EDIT:マルチプロセスは良い提案ではありませんでした。削除されました。

編集: この種のものは、Python では非常に単純です:

import threading, Queue

Stop = object()

def consumer(real_dict, queue):
    while True:
        try:
            item = queue.get(timeout=100)
            if item == Stop:
                break
            user, submission = item
            real_dict[user] = submission
        except Queue.Empty:
            continue

q = Queue.Queue()
thedict={}

t = threading.Thread(target=consumer, args=(thedict,q,))
t.start()

次に、試すことができます:

>>> thedict
{}
>>> q.put(('foo', 'bar'))
>>> thedict
{'foo': 'bar'}
>>> q.put(Stop)
>>> q.put(('baz', 'bar'))
>>> thedict
{'foo': 'bar'}
于 2012-05-08T18:24:05.633 に答える
1

Web アプリケーションとキャッシュの間で大量のデータをやり取りしているようです。それはもう問題です。パターンが次のようになる可能性があるため、疑うのも当然です(これsubは各スレッドにローカルであることを思い出してください)。

スレッド A スレッド B キャッシュ
--------------------------------------------
                                [A]=P、[B]=Q
サブ = get()
   [A]=P、[B]=Q
>>>> 一時停止
                サブ = get()
                   [A]=P、[B]=Q
                サブ[B] = Y
                   [A]=P、[B]=Y
                アップデート(サブ)
                                [A]=P、[B]=Y
                >>>> 一時停止
サブ[A] = X
   [A]=X、[B]=Q
アップデート(サブ)
                                [A]=X、[B]=Q !!!!!!!!

この種のパターンは実際に発生する可能性があり、状態が一掃されます。また、スレッド A は通常、すべてではなく、現在のユーザーについてのみ知る必要があるため、非効率的です。

これは大量のロックによって修正できますが、それは恐ろしく非効率的です。そのため、転送するデータを大幅に減らすように再設計する必要があります。これにより、パフォーマンスが向上し、必要なロックの量が減少します。

于 2012-05-08T18:26:40.947 に答える
1

これは、より大きな設計上の問題のように見えるため、答えるのがより難しい質問の 1 つです。

この問題の 1 つの潜在的な解決策は、これが更新される明確に定義された場所を 1 つ持つことです。たとえば、キャッシュの更新だけに特化した別のサービスをセットアップしたい場合があります。または、これらの更新が時間の制約を受けない場合は、タスク キューの使用を検討することもできます。

別の解決策: 各アイテムに個別のキーを与え、キーのリストを個別のキーの下に保存することができます。これは必ずしも問題を解決するわけではありませんが、管理しやすくなります。個々のスレッドが送信キャッシュ全体を上書きすることを心配する代わりに、その中の個々の要素を上書きすることだけを心配する必要があります。

インフラストラクチャに新しい部分を追加する時間があれば、Redis、より具体的にはRedis ハッシュ[1] を検討することを強くお勧めします。その理由は、Redis がこの問題を箱から出してすぐに処理でき、memcache を使用した場合とほぼ同じ速度で処理できるからです (ただし、自分でベンチマークすることをお勧めします)。

[1] 注: このリンクは、簡単な Google 検索で見つけたもので、まだ確認していません。その正しさを保証するものではありません。

于 2012-05-08T18:49:16.090 に答える