2

Python でマルチスレッド アプリを使用しており、複数のプロデューサー スレッドを作成し、DB からデータを抽出します。データはチャンクで抽出されます。したがって、スレッドが制限値を使用して sql ステートメントを作成する部分は、ロック内に保持されます。また、スレッドが同時にクエリを実行できるようにするために、query() 関数はロックの外側に保持されます。その後、結果フェッチ部分は再びロックされます。以下はコード スニペットです。

with UserAgent.lock:
    sqlGeoTarget = "call sp_ax_ari_select_user_agent_list('0'," + str(self.chunkStart) + "," + str(self.chunkSize) + ",1);"
    self.chunkStart += self.chunkSize

self.dbObj.query(sqlGeoTarget)
print "query executed. Processing data now..."+sqlGeoTarget

with UserAgent.lock:
    result = self.dbObj.fetchAll()
    self.dbObj.dbCursor.close()

しかし、このコードは致命的なエラーを生成しますsegmentation fault (core dumped)。すべてのコードをロックすると、正常に実行されるからです。データをフェッチした後、明示的にカーソルを閉じます。query() 関数が再度起動されるとカーソルが再び開かれます。

このコードは という名前のクラス内にあり、 という名前のクラスUserAgentの共有リソースですProducer。したがって、データベース オブジェクトは共有されます。したがって、問題領域の 99% は、db オブジェクトが共有されているため、クエリを同時にヒットし、カーソルを閉じているため、結果セットが台無しになっている必要があります。しかし、この問題を解決し、db クエリの同時実行を実現するにはどうすればよいでしょうか?

4

1 に答える 1

7

スレッド間で接続を再利用しないでください。代わりに、スレッドごとに新しい接続を作成してください。

MySQLdb ユーザー ガイドから:

MySQL プロトコルは、同じ接続を使用して一度に複数のスレッドを処理することはできません。以前のバージョンの MySQLdb の一部では、ロックを使用して 2 のスレッドセーフを実現していました。標準の Cursor クラス ( を使用mysql_store_result()) を使用してこれを達成するのはそれほど難しくありませんが、SSCursor ( を使用しmysql_use_result()ます。後者では、すべての行を確保する必要があります)別のクエリが実行される前に読み取られました. カーソルがクエリを実行するときにトランザクションが開始され、COMMITまたはROLLBACKConnection オブジェクトによって実行されます。2 つのスレッドは、クエリの実行中に接続を共有できないだけでなく、トランザクションの進行中に接続を共有することもできません。これにより、コードが非常に複雑になり、価値がなくなります。

これの一般的な結論は次のとおりです。スレッド間で接続を共有しないでください。MySQLサーバーは接続ごとに個別のスレッドを実行するため、あなたや私の努力の価値はありません。最終的には、パフォーマンスが低下する可能性があります. プール内のキャッシュ接続などを確実に実行して、それらの接続を一度に 1 つのスレッドに割り当てることができます。2 つのスレッドが同時に接続を使用できるようにすると、MySQL クライアント ライブラリはおそらくアップチャックして停止します。あなたは警告されました。

鉱山を強調します。

代わりに、スレッド ローカル ストレージまたは専用の接続プール ライブラリを使用してください。

于 2012-11-28T11:57:40.527 に答える