「スレッド」モジュールを使用するPythonプログラムがあります。1秒ごとに、プログラムはWebからデータを取得する新しいスレッドを開始し、このデータをハードドライブに保存します。これらの結果を保存するためにsqlite3を使用したいのですが、動作させることができません。問題は次の行にあるようです:
conn = sqlite3.connect("mydatabase.db")
以前は、すべての結果をCSVファイルに保存していましたが、これらのファイルロックの問題はありませんでした。これがsqliteで可能になることを願っています。何か案は?
コンシューマープロデューサーパターンを使用できます。たとえば、スレッド間で共有されるキューを作成できます。 Webからデータを取得する最初のスレッドは、このデータを共有キューに入れます。データベース接続を所有する別のスレッドは、キューからデータをデキューし、データベースに渡します。
一般的な考えに反して、sqlite3の新しいバージョンdoは、複数のスレッドからのアクセスをサポートします。
これは、オプションのキーワード引数check_same_thread
を使用して有効にできます。
sqlite.connect(":memory:", check_same_thread=False)
以下は mail.python.org.pipermail.1239789 にあります
解決策を見つけました。なぜpythonドキュメンテーションにこのオプションに関する単語が1つもないので、接続関数に新しいキーワード引数を追加する必要があり、そこからカーソルを作成できるようになります。異なるスレッド。
sqlite.connect(":memory:", check_same_thread = False)
私にとって完璧に機能します。もちろん、今後はdbへの安全なマルチスレッドアクセスに注意する必要があります。とにかく助けようとするためのすべてのthx。
これにはスレッドを使用しないでください。これは、 twisted の簡単なタスクであり、とにかく大幅にさらに先に進むでしょう。
1つのスレッドのみを使用し、要求の完了によりイベントをトリガーして書き込みを実行します。
twistedはスケジューリング、コールバックなどを処理します。結果全体を文字列として渡すか、ストリームプロセッサを介して実行できます( Twitter API と friendfeed API が両方とも起動します)結果がまだダウンロードされているため、発信者にイベントが送信されます)。
データで何をしているのかに応じて、完全な結果を完全にsqliteにダンプするか、クックしてダンプするか、読み取り中にクックして最後にダンプすることができます。
私はあなたがgithubで欲しいものに近い何かをする非常にシンプルなアプリケーションを持っています。 pfetch (並列フェッチ)と呼びます。スケジュールに従ってさまざまなページを取得し、結果をファイルにストリーミングし、オプションで各ページが正常に完了したらスクリプトを実行します。また、条件付きGETのような派手な機能も実行しますが、それでもあなたがしていることの良い基盤になるでしょう。
multiprocessing に切り替えます。複数のCPUを使用することで、複数のコアを使用するだけでなく、はるかに優れた拡張性があり、インターフェイスはpython threading module。
または、ALiが提案したように、単に SQLAlchemyのスレッドプーリングメカニズム を使用します。それはあなたのためにすべてを自動的に処理し、それらのいくつかを引用するだけで多くの追加機能を備えています:
または、私のように怠け者の場合は、 SQLAlchemy を使用できます。それはあなたのためにスレッディングを処理します、( スレッドローカル、およびいくつかの接続プーリングを使用して )、そしてそれをする方法は 設定可能 です。
追加のボーナスとして、同時アプリケーションにSqliteを使用することが災害になると気づいた場合、MySQLやPostgresなどを使用するためにコードを変更する必要はありません。ただ切り替えることができます。
このエラーの原因となるマルチスレッドで同じカーソルを使用しないで同じスレッドで同じカーソルを使用するには、データベースに対してevery transactionの後にsession.close()
を使用する必要があります。
私はEvgenyの答えが好きです-通常、キューはスレッド間通信を実装する最良の方法です。完全を期すために、他のオプションを次に示します。
OperationalError
を修正しますが、パフォーマンスのオーバーヘッドにより、このような接続のオープンとクローズは一般的にNo-Noです。threading.Lock() を使用します
Scrapy は私の質問に対する潜在的な答えのようです。そのホームページは私の正確なタスクを説明しています。 (コードの安定性はまだわかりませんが。)
プログラムの並行性を設計する必要があります。 SQLiteには明確な制限があり、それらに従う必要があります。 [〜#〜] faq [〜#〜] (次の質問も参照)を参照してください。
上記の回答のいずれにもベンチマークが見つからなかったため、すべてをベンチマークするテストを作成しました。
3つのアプローチを試しました
ベンチマークからの結果と要点は次のとおりです。
My SO answer [〜#〜] here [〜#〜] で、ベンチマークのコードと完全なソリューションを見つけることができます。
Y_serial Pythonデータ永続化のためのモジュール: http://yserial.sourceforge.net
単一のSQLiteデータベースを取り巻くデッドロックの問題を処理します。並行性への要求が重くなった場合、多くのデータベースのクラスFarmを簡単に設定して、確率的な時間で負荷を分散させることができます。
これがあなたのプロジェクトに役立つことを願っています...それは10分で実装するのに十分簡単であるべきです。