簡體   English   中英

Python線程偶爾無法返回

[英]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語句放入線程方法中,以准確確定其卡住的位置,然后從那里去。 但是,沒有其他並發問題跳出來。

編輯:

順便說一句,您在這里所做的事情可以更干凈地實現為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調用所做的get_backup_list ,您可能會發現它作為multiprocessing.Pool會更好地執行,因為它能夠繞過全局解釋器鎖(GIL),從而防止Python線程同時在多個CPU內核上執行。 看起來您的代碼可能是受I / O約束的,因此ThreadPool可能會很好。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM