2014-02-26 15 views
1

我有一個使用Perl線程模塊創建一些線程的腳本,並且每個線程都創建了一個到SQLite dbfile的數據庫連接。在線程內部有一個從文件句柄讀取的while循環,用於向zcat處理的文件打開管道輸入。我試圖爲每個線程正在處理的每個X行提交事務。當我嘗試在while循環之外使用$dbh->begin_work時,單個線程會阻止其餘的線程。當我把$dbh->begin_work放在while循環內時,它們不會互相阻塞。後者基本上是自動提交每個$dbh->do("insert...")聲明。爲什麼$dbh->begin_work似乎不能在while循環之外工作?Perl DBD :: SQLite - while循環塊線程之外的begin_work?

$dbh->begin_work; # This blocks the while loops in other threads 

while ($row = <$gz>) { 
    $dbh->begin_work; # This does not block 
    @values = split('\|', $row); 
    @node_ids = split ',', $values[21] 
    for $node_id (@node_ids) { 
    $dbh->do("insert ...."); 
    } 
    $dbh->commit; # This does not block 
} 

$dbh->commit; # This blocks the while loops in other threads 

我正在使用DBD:SQLite版本1.29。我試過使用* sqlite_use_immediate_transaction *,但直到版本1.38_01才似乎是必需的。

+0

請提供一個問題的實際演示。另外,確保你在使用它的線程中創建dbh。如果這沒有幫助,它可能是SQLite的限制。 – ikegami

+0

你檢查過線程上的SQLite文檔嗎? https://www.sqlite.org/threadsafe.html – oalders

回答

0

我所有的鎖的經驗是在其他數據庫,我不知道你期待什麼(在我看來是begin_work按設計工作),但如果你把這個:

unless (++$count % X) { $dbh->commit; $dbh->begin_work; } 

插入後,刪除循環內的其他提交/開始,看起來它會做你想做的事,釋放鎖並進入下一組鎖的隊列。

+0

begin_work看起來像提交X行一樣工作,但是發生的事情是,當線程1處於事務線程中時,2停止讀取gz輸入。我期待這兩個線程同時建立交易,然後輪流提交X長交易。當begin_work/commit在循環之外時,每個線程在100%CPU上運行,但一次只能運行一個線程。當begin_work/commit在裏面時,多個線程似乎同時運行,但是大約有20%的cpu。但是我猜測,如果他們實際上倒退了四分之一,那麼頂級節目可能會達到20%。 –

+0

我認爲這是可以預料的,特別是如果你在表格上有索引,這些索引將被鎖定直到提交。還有其他因素,如身份密鑰。如果你的插入在插入時增加了id,你不能指望它在提交時重新計算它們,因爲另一個線程在它提交之前已經接受了這些數字。如果你沒有索引,它可能會工作(但可能不),或者如果你可以物理分區表(我懷疑SQLite支持),這將允許表在不同的地方同時增長。 – albe