2011-07-16 93 views
3

私はArch Linux x86_64でPython 3.2.1を使用しています。私は、次のようないくつかのコードとねじ、タイミングループ内のsqliteデータベースを更新しようとしている
:残念ながら返しpython:キューとスレッド間でsqlite接続を共有するには?

import sqlite3 
from threading import Timer 
from queue import Queue 

class DBQueue(Queue): 
    def give(self, item): 
     self.task_done() 
     self.join() 
     self.put(item) 
     return True 


def timer(): 
    print('A') 
    Timer(3, add).start() 


def add(): 
    print('B') 
    db = qdb.get() 
    cur = db.cursor() 
    cur.execute('INSERT INTO Foo (id) VALUES (NULL)') 
    qdb.give(db) 
    timer() 

qdb = DBQueue() 
# SOLUTION #1: 
# qdb.put(sqlite3.connect(':memory:', check_same_thread=False)) 
# SOLUTION #2: see Eli Bendersky's answer 
qdb.put(sqlite3.connect(':memory:')) 
db = qdb.get() 
cur = db.cursor() 
cur.execute('CREATE TABLE Foo (id INTEGER PRIMARY KEY)') 
qdb.give(db) 
timer() 

A 
B 
Exception in thread Thread-1: 
Traceback (most recent call last): 
    File "/usr/lib/python3.2/threading.py", line 736, in _bootstrap_inner 
    self.run() 
    File "/usr/lib/python3.2/threading.py", line 942, in run 
    self.function(*self.args, **self.kwargs) 
    File "/home/dario/dev/python/prova/src/prova4.py", line 27, in add 
    cursor = db.cursor() 
sqlite3.ProgrammingError: SQLite objects created in a thread can only be used in that same thread.The object was created in thread id 140037302638336 and this is thread id 140037262886656 

を唯一のカーソルの共有はしていませんより良い結果を得る:

conn = sqlite3.connect(':memory:') 
qdb.put(conn.cursor()) 

私はキューを使ってスレッド間でデータベースを共有する方法を全く理解していない誰も助けてくれませんか? ありがとうございました!

+1

2つのセント:Pythonでスレッドを使用せず、代わりにマルチプロセッシングを使用し、各プロセスで別々のデータベース接続を使用してください。 – James

+0

ありがとう、私はマルチプロセッシングを見ていきますが、私はEliの答えで私のコメントを見ています。私は変更をコミットしたくないので、複数の接続を避けたいと思います。この状況でキューを使用することは本当に不可能ですか? – kynikos

+0

'check_same_thread = False'でデータベースに接続すると、キューを使用していると危険ですか? – kynikos

答えて

2

Queueは必要ありません.2つのスレッドから同じデータベースに別々の接続を使用するだけです。個別の接続がデータをDBにコミットするときには、順序付けの点ではあまり期待しないでください。 DBに同時にアクセスするプログラムの2つの異なるインスタンスがあるかのように扱います。何らかの理由で、あなたは絶対に接続を共有しなければならないと感じた場合は


は、これを試してください:あなたは1つのスレッドからSQLiteのオブジェクトを作成し、別でそれらを使用することの問題をヒットするので、なぜタスクを委任していません1つのスレッドでdb/connectionを処理し、Queueを介して他のスレッドと通信できるようにします。より具体的には:

  • スレッドDB_thread:接続を「所有」します。キュー内のコマンドを他のスレッドから取得して実行し、結果を「結果キュー」に配置します。
  • スレッドA、B、C:「コマンド」をキューに渡し、結果キューから結果を取得します。

これらのコマンドはSQLiteオブジェクトではありません。

+0

実際のプログラムでは、メモリではなくファイルデータベースを使用しています。私は明示的に保存するまで変更をコミットしたくありません。 pythonのドキュメントでは、「データベースが複数の接続でアクセスされ、プロセスの1つがデータベースを変更すると、トランザクションがコミットされるまでSQLiteデータベースはロックされます」と表示されますが、ここで結果を報告します。 – kynikos

+0

私が思い出したように、複数の接続を使用すると、他の接続で使用できるように変更をコミットする必要があります。そのようなことは避けてください。 sqliteでキューを使用することは本当に不可能ですか?それ以外の場合は、データベース全体をコピーする必要があります:メモリ:または一時ファイルを使用する... – kynikos

+0

@kynikos:私は答えを –

関連する問題