2014-07-03 62 views
0

我正在研究一個多線程的Python腳本,它接收一個文件名列表並將它們放在一個隊列中。大多數時候它可以工作,但是我偶爾會發現它被卡住了,'ps -efL'會顯示兩個線程爲python腳本打開。我用strace跟着它,並且6個線程中有5個返回了,但是一個只是掛在futex上,永遠等待。Python線程偶爾無法返回

下面是有問題的代碼塊。

threads = 6 

for fileName in fileNames: 
    queue.put(fileName) 

for i in range(threads): 
    t = threading.Thread(target=get_backup_list, args=(queue,dbCreds,arguments.verbose,arguments.vault)) 
    activeThreads.append(t) 
    t.start() 

for activeThread in activeThreads: 
    activeThread.join() 


def get_backup_list(queue,dbCreds,verbosity,vault): 
    backupFiles = [] 

    while True: 
    if queue.empty() == True: 
     return 
    fileName = queue.get() 
    try: 
     fileInfo = lookup_file_by_path(fileName,dbCreds,vault) 
     if not fileInfo: 
     start = time.time() 
     attributes = get_attributes(fileName,verbosity) 
     end = time.time() - start 
     if verbosity: print("finished in ") + str(end) + (" seconds") 
     insert_file(attributes,dbCreds,vault) 
     fileInfo = lookup_file_by_path(fileName,dbCreds,vault) 

    except Exception, e: 
     print("error on " + fileName + " " + str(e)) 

    return 

def lookup_file_by_path(path,dbCreds,vault): 
    attributes = {} 
    conn = mdb.connect(dbCreds['server'] , dbCreds['user'], dbCreds['password'], dbCreds['database'], cursorclass=MySQLdb.cursors.DictCursor); 
    c = conn.cursor() 
    c.execute('''SELECT * FROM {} where path = "%s" '''.format(vault) % (path)) 
    data = c.fetchone() 
    if data: 
    for key in data.keys(): 
     attributes[key] = data[key] 
    conn.close 
    return attributes 

我在做一些根本錯誤的事情,導致競爭狀態?或者是有什麼我失蹤了。

感謝, 托馬斯Ç

+0

那麼,'conn.close'缺少一對括號,調用'queue.empty'而不是直接去'get'(可能用'block = False')通常是一個壞主意。 – user2357112

回答

3

。在你的代碼中的競爭條件:

while True: 
    if queue.empty() == True: 
     return 
    fileName = queue.get() 

首先,線程檢查隊列爲空。如果不是,它會嘗試阻止get。但是,在撥打queue.empty()queue.get之間的時間內,另一個線程可能會佔用隊列中的最終項目,這意味着get呼叫將永遠阻止。你應該這樣做,而不是:

try: 
    fileName = queue.get_nowait() 
except Queue.Empty: 
    return 

如果不解決這個問題,你可以拋出一些print語句到螺紋的方法來確定它的確切位置卡住,並從那裏走。但是,沒有其他併發問題突然出現在我身上。

編輯:

順便說一句,你在這裏做什麼可以爲ThreadPoolmultiprocessing.Pool更加清潔執行:

from multiprocessing.pool import ThreadPool 
from functools import partial 

def get_backup_list(dbCreds, verbosity, vault, fileName): 
    backupFiles = [] 
    fileInfo = lookup_file_by_path(fileName,dbCreds,vault) 
    ... 

if __name__ == "__main__": 
    pool = ThreadPool(6) # You could use a multiprocessing.Pool, too 
    func = partial(get_backup_list, dbCreds, arguments.verbose, arguments.vault) 
    pool.map(func, fileNames) 
    pool.close() 
    pool.join() 

根據多少工作,每次調用get_backup_list是你可能會發現它在multiprocessing.Pool中表現更好,因爲它可以解決全局解釋器鎖(GIL),它可以防止Python線程同時在CPU內核間執行。它看起來像你的代碼可能是I/O綁定,但是,所以ThreadPool可能會很好。

+0

我敢打賭,發生了什麼,讓我測試幾次。 – user2554479

+0

這是修復,謝謝!我開始時看到了ThreadPool,但我不確定最佳路徑是什麼。我會再試一次。 – user2554479