[英]Python thread occasionally fails to return
我正在研究一種多線程Python腳本,該腳本接受文件名列表並將其放入隊列中。 在大多數情況下,它可以工作,但是我偶爾會發現它卡住了,並且“ ps -efL”將顯示兩個為python腳本打開的線程。 我緊隨其后的是strace,返回了6個線程中的5個,但是其中一個只是掛在futex中而永遠等待。
這是有問題的代碼塊。
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
我在這里做的根本是錯誤的事情導致了比賽狀況嗎? 或者還有其他我想念的東西。
謝謝,托馬斯·C
您的代碼中存在競爭條件:
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
語句放入線程方法中,以准確確定其卡住的位置,然后從那里去。 但是,沒有其他並發問題跳出來。
編輯:
順便說一句,您在這里所做的事情可以更干凈地實現為ThreadPool
或multiprocessing.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
調用所做的get_backup_list
,您可能會發現它作為multiprocessing.Pool
會更好地執行,因為它能夠繞過全局解釋器鎖(GIL),從而防止Python線程同時在多個CPU內核上執行。 看起來您的代碼可能是受I / O約束的,因此ThreadPool
可能會很好。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.