2012-11-28 62 views
0

我在python中有一個多線程應用程序,其中我創建了多個生產者線程,並從數據庫中提取數據。數據以塊形式提取。所以線程創建帶限制值的sql語句的部分被保存在鎖內。爲了讓線程同時執行查詢,query()函數保持在鎖之外。然後結果提取部分再次保持在鎖定下。以下是代碼片段:python中的多線程應用程序中的分段錯誤錯誤

with UserAgent.lock: 
    sqlGeoTarget = "call sp_ax_ari_select_user_agent_list('0'," + str(self.chunkStart) + "," + str(self.chunkSize) + ",1);" 
    self.chunkStart += self.chunkSize 

self.dbObj.query(sqlGeoTarget) 
print "query executed. Processing data now..."+sqlGeoTarget 

with UserAgent.lock: 
    result = self.dbObj.fetchAll() 
    self.dbObj.dbCursor.close() 

但是,此代碼會生成致命錯誤segmentation fault (core dumped)。因爲如果我把所有的代碼都鎖住了,它就可以正常運行。我在獲取數據後明確地關閉了光標,當query()函數再次觸發時,它會重新打開。

此代碼位於名爲UserAgent的類中,它是名爲Producer的類的共享資源。因此,數據庫對象是共享的。所以問題區域99%必須是因爲db對象共享同時查詢和關閉遊標然後必須搞亂結果集。但那麼如何解決這個問題並實現併發db查詢的執行?

回答

5

不要在線程間重複使用連接。相反,爲每個線程創建一個新的連接。

從MySQLdb的用戶指南:

MySQL的協議不能使用在一次相同的連接處理多個線程。一些較早版本的MySQLdb使用鎖定來實現2的線程安全性。雖然使用標準光標類(其使用mysql_store_result())並不難完成,但它由SSCursor(其使用mysql_use_result();使用mysql_use_result();而後者必須確保所有在執行另一個查詢之前,行已經被讀取,事務的增加會使事務更加複雜,因爲事務在光標執行查詢時開始,但當Connection對象執行COMMITROLLBACK時結束,兩個線程根本無法共享一個事務正在進行時的連接,除了在查詢執行過程中不能共享它之外,代碼過於複雜,並不值得。

這樣的一般結果是: 不要共享線程間的連接。這真的不值得你的努力或我的努力,最終可能會損害性能,因爲MySQL服務器爲每個連接運行一個單獨的線程。您當然可以做一些事情,比如緩存池中的連接,並且一次將這些連接提供給一個線程。如果你讓兩個線程同時使用一個連接,MySQL客戶端庫可能會掛起並死亡。你被警告了。

強調我的。

改爲使用thread local storagededicated connection pooling library

+0

好的,這是一些非常有用的信息。現在我有一個設計相關的問題。這個類的UserAgent應該是一個自包含的類,它的對象曾經實例化,創建一個db連接,當調用getData()時,它將把數據返回給調用者。現在,如果我必須讓線程訪問這個,我需要爲每個線程分別建立數據庫連接。那麼我怎麼能做到這一點?我應該在生產者中創建數據庫連接並將其傳遞給'getData()'。這聽起來有點奇怪,你會建議什麼? – Shades88

+1

使用本地線程:[Python中的線程本地存儲](http://stackoverflow.com/q/1408171) –

+0

或者,使用專用[連接池庫](http://code.google.com/p/) pysqlpool /)。 –