我peewee在多臺機器上使用 SQLite 資料庫,我遇到了各種OperationalError, DataBaseError. 這顯然是多執行緒的問題,但我根本不是這方面的專家,也不是 SQL 方面的專家。這是我的設定和我嘗試過的。
設定
我peewee用來記錄機器學習實驗。基本上,我有多個節點(例如,不同的計算機)運行一個 python 檔案,并且所有節點都寫入共享位置中的同一個 base.db檔案。最重要的是,我需要從我的筆記本電腦進行一次讀取訪問,以查看發生了什么。最多有大約 50 個不同的節點來實體化資料庫并在其上寫入內容。
我試過的
起初,我使用了 SQLite 物件:
db = pw.SqliteDatabase(None)
# ... Define tables Experiment and Epoch
def init_db(file_name: str):
db.init(file_name)
db.create_tables([Experiment, Epoch], safe=True)
db.close()
def train():
xp = Experiment.create(...)
# Do stuff
with db.atomic():
Epoch.bulk_create(...)
xp.save()
這作業正常,但有時我的作業因資料庫被鎖定而崩潰。然后,我了解到 SQLite 每個連接只處理一個寫操作,這導致了問題。
所以我轉向SqliteQueueDatabaseas,根據檔案,如果“如果您想要從多個執行緒對 SQLite 資料庫進行簡單的讀寫訪問”,它會很有用。我還添加了我在其他執行緒上發現的那些據說很有用的關鍵字。
代碼如下所示:
db = SqliteQueueDatabase(None, autostart=False, pragmas=[('journal_mode', 'wal')],
use_gevent=False,)
def init_db(file_name: str):
db.init(file_name)
db.start()
db.create_tables([Experiment, Epoch], safe=True)
db.connect()
除了db.atomic零件之外,保存東西也是如此。然而,不僅寫查詢似乎遇到錯誤,我幾乎不再有權訪問資料庫進行讀取:它幾乎總是很忙。
我的問題
What is the right object to use in this case? I thought SqliteQueueDatabase was the perfect fit. Are pooled database a better fit? I'm also asking this question because I don't know if I have a good grasp on the threading part: the fact that multiple database object are initialized from multiple machines is different from having a single object on a single machine with multiple threads (like this situation). Right? Is there a good way to handle things then?
Sorry if this question is already answered in another place, and thanks for any help! Happy to provide more code if needed of course.
uj5u.com熱心網友回復:
Sqlite 一次只支持一個撰寫器,但在使用 WAL 模式時,多個讀取器可以打開資料庫(即使連接了一個撰寫器)。對于 peewee,您可以啟用 wal 模式:
db = SqliteDatabase('/path/to/db', pragmas={'journal_mode': 'wal'})
另一件重要的事情是,在使用多個寫入器時,要使您的寫入事務盡可能短。可以在此處找到一些建議:https : //charlesleifer.com/blog/going-fast-with-sqlite-and-python/在“事務、并發和自動提交”標題下。
另請注意,SqliteQueueDatabase 適用于具有多個執行緒的單個行程,但如果您有多個行程,則根本無濟于事。
uj5u.com熱心網友回復:
Inded,在@BoarGules 發表評論后,我意識到我混淆了兩個截然不同的事情:
- 在一臺機器上有多個執行緒:這里
SqliteQueueDatabase非常適合 - 擁有多臺機器,有一個或多個執行緒:這基本上就是互聯網的作業方式。
所以我最終安裝了 Postgre。一些鏈接,如果它對追隨我的人有用,對于linux:
- 安裝 Postgre。如果按照官方檔案的第 17章和第 19章沒有 root 權限,則可以從源代碼構建它。
- 您可以使用
pgloader. 但同樣,如果您沒有合適的庫并且不想構建所有內容,您可以手動完成。我做了以下,不確定是否存在更直接的解決方案。
- 將您的表格匯出為 csv(遵循@coleifer 的評論):
models = [Experiment, Epoch]
for model in models:
outfile = '%s.csv' % model._meta.table_name
with open(outfile, 'w', newline='') as f:
writer = csv.writer(f)
row_iter = model.select().tuples().iterator()
writer.writerows(row_iter)
- 在新的 Postgre 資料庫中創建表:
db = pw.PostgresqlDatabase('mydb', host='localhost')
db.create_tables([Experiment, Epoch], safe=True)
- 使用以下命令將 CSV 表復制到 Postgre db:
COPY epoch("col1", "col2", ...) FROM '/absolute/path/to/epoch.csv'; DELIMITER ',' CSV;
其他表也是如此。
它對我來說很好用,因為我只有兩張桌子。如果你有更多,可能會很煩人。pgloader在這種情況下似乎是一個非常好的解決方案,如果您可以輕松安裝它。
更新
一開始我無法創建物件peewee。我有完整性錯誤:似乎idPostgre(帶有RETURNING 'epoch'.'id'子句)回傳的 正在回傳一個已經存在的 id。據我了解,是因為在使用該COPY命令時沒有呼叫增量。因此,它只回傳 id 1,然后是 2,依此類推,直到到達一個不存在的 id。為了避免經歷所有這些失敗的創建,您可以直接編輯控制RETURN子句的迭代器,使用:
ALTER SEQUENCE epoch_id_seq RESTART WITH 10000
并替換10000為SELECT MAX("id") FROM epoch, 1 中的值。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/318755.html
標籤:python multithreading sqlite peewee
上一篇:與ProcessExplorer的TID對應的System.Threading.Thread的屬性/屬性/欄位是什么?
