我正在嘗試編寫一個多線程Python應用程序,其中線程之間共享單個SQlite連接。我無法得到這個工作。真正的應用程序是一個cherrypy web服務器,但下面的簡單代碼演示了我的問題。如何在多線程Python應用程序中共享單個SQLite連接
下面運行示例代碼需要做些什麼改變?
當我運行THREAD_COUNT這個程序設置爲1時,它工作正常,我的數據庫更新,因爲我期望(即字母「X」被添加到SectorGroup列中的文本值)。
當我將THREAD_COUNT設置爲大於1的任何值時,除1以外的所有線程都會過早地終止與SQLite相關的異常。不同的線程拋出不同的異常(沒有明顯的模式),包括:
OperationalError: cannot start a transaction within a transaction
(發生在UPDATE
語句)
OperationalError: cannot commit - no transaction is active
(發生在.commit()調用)
InterfaceError: Error binding parameter 0 - probably unsupported type.
(發生在UPDATE
和SELECT
陳述)
IndexError: tuple index out of range
(這其中有我完全摸不着頭腦,它發生在聲明group = rows[0][0] or ''
,但只有當多個線程運行)
下面是代碼:
CONNECTION = sqlite3.connect('./database/mydb', detect_types=sqlite3.PARSE_DECLTYPES, check_same_thread = False)
CONNECTION.row_factory = sqlite3.Row
def commands(start_id):
# loop over 100 records, read the SectorGroup column, and write it back with "X" appended.
for inv_id in range(start_id, start_id + 100):
rows = CONNECTION.execute('SELECT SectorGroup FROM Investment WHERE InvestmentID = ?;', [inv_id]).fetchall()
if rows:
group = rows[0][0] or ''
msg = '{} inv {} = {}'.format(current_thread().name, inv_id, group)
print msg
CONNECTION.execute('UPDATE Investment SET SectorGroup = ? WHERE InvestmentID = ?;', [group + 'X', inv_id])
CONNECTION.commit()
if __name__ == '__main__':
THREAD_COUNT = 10
for i in range(THREAD_COUNT):
t = Thread(target=commands, args=(i*100,))
t.start()
他們爲什麼需要共享連接?這似乎是一個壞主意。 – ebarr
您是否閱讀過http://docs.python.org/2/library/sqlite3.html#multithreading?只需創建一個連接*每個線程*。 –
基本上,如果您共享線程之間的連接,則需要執行自己的鎖定;請參閱http://bugs.python.org/issue16509瞭解該方向的提示。你最好使用SQLAlchemy並讓它處理池(它也增加了一個有效的工作單元排隊系統)。 –