1

私は現在、Python での Web アプリケーションの WSGI 仕様に精通しています。各リクエストの一意性を観察するために、現在スレッド ID 番号を表示するだけの小さなアプリケーションを呼び出すように Apache (mod-wsgi を使用) をセットアップしました。

import thread

def application(environ, start_response)
    start_response('200 Ok', [('Content-type', 'text/plain')])
    output = "current thread id: %s" % thread.get_ident()
    return [output]

しばらくすると、同じスレッドが後続のリクエストで再利用されていることに気付きました。

私の理解が正しければ、アプリケーションに「コンテキスト固有の」変数を持たせるには、次のようなスキームでそれらを保存する必要があります。

lock = thread.allocate_lock()
lock.acquire()
thread_id = get_ident()
threadsafe[thread_id]['user'] = request.username
lock.release()

その後、同様の方法で、アプリケーションの別の部分からそれらにアクセスできます。この場合の唯一の保証は、値がその特定のスレッドに属していることです。ただし、同じスレッドを使用するリクエストは、依然としてお互いに足を踏み入れる可能性があります (たとえば、前のリクエストの残りの値にアクセスするリクエスト)。私の結論は、「thread_id」に加えて、各リクエストを真に一意の方法で処理するには、同じスレッドを使用するリクエストを区別できる別のキーが必要になるということです。

uuidなどの一意のキーを使用して、これを行うことができました

lock.acquire()
uuid = uuid.uuid4()
thread_id = get_ident()
threadsafe[(thread_id, uuid)]['user'] = request.username
lock.release()

ただし、これは、後で thread_id を取得できるのと同じ方法で、スレッドセーフな方法で uuid 値も取得する方法があることを意味します。

私は正しい結論を導き出しましたか?もしそうなら、どうすればその追加のキーを取得できますか?

編集

私の問題が誤った二分法であることに気づきました。実際にはこれが不可能な場合でも、スレッドがそれ自体と同時に実行される可能性があるという観点で物事に取り組んでいます。同じスレッドを使用するリクエストは、連続して実行する必要があります。したがって、実際には uuid を使用してスレッドの古い値の使用を避けることができましたが、それはそれをスレッド保存値自体として保存した後でのみでした。

# somewhere early in the request
threadsafe[thread_id]['current_uuid'] = uuid.uuid4()

# later
lock.acquire()
thread_id = get_ident()
uuid = threadsafe[thread_id]['current_uuid']
threadsafe[(thread_id, uuid)]['user'] = request.username
lock.release()
4

2 に答える 2

1

この回答は、@ user590028 の回答のコメントで開発された新しい情報に基づいています。

あなたの目標は、スレッドセーフな永続データを持つことだと言いました。あなたは WSGI 仕様に慣れているとも言ったので、このリンクは特に関連があると思います: Application_Global_Variables

...グローバル データは使用できますが、その単一プロセスのコンテキスト内で安全に再利用できるデータをキャッシュするためにのみ使用できます。どのプロセスで実行されるかに関係なく、すべての要求ハンドラーに表示される必要がある情報を保持する手段として、グローバル データを使用することはできません。

アプリケーションは複数のスレッドで実行されているだけでなく、複数のプロセスで実行されている可能性があります。上記のリンクによると、永続的なデータ (現在の要求のそれを超える) の推奨される解決策は、外部ストレージ ソリューション (ファイルシステム、データベース、memcached など) を使用することです。

アップデート

状態情報を保存するためにロックでやろうとしていることは、完全に不必要に思えます。すべてのリクエストは、何があっても一意であると見なす必要があります。クライアント側のユーザーがアプリケーションに対して 10 個のリクエストを行い、それらのリクエスト間でデータを保持したい場合は、リクエストが新しい (セッションを含まない) ときにクライアントに対して最初に確立する Cookie のようなセッション キーを使用する必要があります。 、そして応答でそれを返し、将来の要求がこのキーを提供することを期待します。その後、この機能を提供することを目的としたライブラリがあります: http://www.ollycope.com/software/pesto/session.html

wsgi アプリケーションにはエントリ ポイントがあります。この場合、例では「アプリケーション」という関数として定義されています。クラスまたは呼び出し可能なものである可能性もあります。スコープのため、変数は本質的にコンテキスト固有です。そのスコープで何をするにしても、同じハンドラーを実行している他のスレッドとはまったく異なります。「アプリケーション」関数は、他の関数を呼び出して、最終的に応答本文を返すまでその変数を渡し、より複雑にすることもできます。リクエストを処理してレスポンスを生成するために必要なすべての機能を含むクラス インスタンスを作成し、独自のインスタンス変数を使用することもできます。

そして、これらの前の 2 つの提案のどちらもあなたが求めていることに当てはまらない場合、データベース、ファイルシステム、memcached、または redis などに実際にデータを保存したいという唯一の可能性があると思います。uuid4 は一意ですが、その値は、応答でそれを渡し、クライアントがそれを返してそのデータに関連付けられたままにする場合にのみ意味があります。

于 2012-04-06T23:18:33.400 に答える
0

あなたが正しいです。スレッド ID は、時間の経過とともに一意であるとは限りません。UUID を考慮してください。str(uuid.uuid4()) のようなもの

于 2012-04-06T22:22:55.127 に答える