3

重い負荷がかかると、ピラミッド Web アプリが py-postgresql 例外をスローすることがわかりpostgresql.exceptions.ProtocolErrorました。一部の検索で、py-postgresql はスレッドセーフではなく、1 つの接続を複数のスレッドで同時に使用できないことが明らかになりました。

ある種のプーリング メカニズムを作成しようとしましたが、それでも ProtocolErrors が発生します :(

私は何を間違っていますか?

まず、いくつかの接続オブジェクトを作成します。

    for x in range(num_db_connections):
        self.pool.append(Connection(conn_string,x))

プール内の各オブジェクトにはdb_lock = threading.Lock()、データベースへの接続が含まれていますself.conn = postgresql.open( conn_string )

次に、接続のロックを取得して、いくつかの作業を行います。workこのコードは多くのスレッドで同時に実行できますが、ロックのために 1 つの接続で2 つのスレッドを同時に実行することはできないと思います。

    time_start = time.time()
    while time.time() - time_start < self.max_db_lock_wait_time:
        for conn in self.pool:
            acquired = conn.db_lock.acquire(False)
            if acquired:
                try:
                        lst = conn.work()
                finally:
                    conn.db_lock.release()
                return lst
        time.sleep(0.05)
    raise Exception('Could not get connection lock in time')

私のコードに欠陥があるのでしょうか、それとも py-postgresql の「スレッドの安全性」の性質を誤解したのでしょうか? 私を助けてください!

4

1 に答える 1

2

ロック外でカーソル オブジェクトを使用していないことを確認しますか?

単なる提案: time.sleep() を使用してロックを「試行」する代わりに、キューを使用して接続オブジェクトをプールから/プールにポップ/プッシュします。これはすでにスレッド セーフであり、タイムアウト パラメータがあります。はるかに効果的です。特に、スレッド数が多く、接続数が少ない場合。(100,000 クエリを実行する必要がある場合、これらの小さなスリープ命令が合計されます。それらすべてにより、応答時間が長くなります。)

于 2012-09-27T19:32:50.773 に答える