對於你的主要問題:
如果你正在做更復雜的事情t這個 - 或者,特別是如果你反覆這樣做 - 你可能需要一個「線程組」類。其中有幾十個是預製的,但如果你不喜歡其中任何一個,自己寫一個就很麻煩。
然後,而不是這樣的:
threadList = []
for argchunk in splitIntoChunks(values, 10):
threadList.append(threading.Thread(target=myThreadFunc, args=argchunk))
...
someTotal = 0
for th in threadList:
th.join()
someTotal += th.resultsAttribute
你可以這樣做:
threadGroup = ThreadGroup.ThreadGroup()
for argchunk in splitIntoChunks(values, 10):
threadGroup.newThread(myThreadFunc, argchunk)
threadGroup.join()
someTotal = sum(th.resultsAttribute for th in threadGroup)
或者,甚至更好,一個完整的線程池庫,這樣你就可以做到這一點:
pool = ThreadPool(10)
for argchunk in splitIntoChunks(values, 100):
pool.putRequest(myThreadFunc, argchunk)
pool.wait()
這裏的優勢是,您可以輕鬆地在10個線程上安排100個作業,而不是10個作業o每個線程不需要維護一個隊列等等。缺點是你不能只迭代線程來獲得返回值,你必須迭代工作 - 理想情況下,你不想保留工作活着直到最後,以便您可以迭代它們。
這給我們帶來了第二個問題,即如何從線程(或作業)中獲取值。有很多種方法可以做到這一點。
你做了什麼工作。你甚至不需要任何鎖定。
使用回調,如你所說,也適用。但請記住,回調將在工作線程上運行,而不是主線程,因此如果它訪問某個全局對象,則需要某種同步。
如果你想反正同步,可能沒有任何好處的回調。例如,如果你所要做的只是求和一堆值,你可以設置total=[0]
,並讓每個線程在鎖內執行total[0] += myValue
。 (當然,在這種情況下,它可能更有意義,只是做在主線程中求和,避免鎖,但如果同化的結果的工作很多更爲強大,這樣的選擇可能不是那麼簡單。)
您也可以使用某種原子對象,而不是顯式鎖定。例如,標準Queue.Queue和collections.deque都是不可分割的,因此每個線程都可以只設置q = Queue.Queue()
,則每個線程推動通過連接你只是重複和總結隊列的值之後做q.push(myValue)
,那麼它的結果。事實上,如果每個線程都只需要推送一次隊列,就可以在隊列本身上執行10次阻塞獲取,之後您就知道group.join()
或pool.wait()
或其他任何會快速返回的隊列。
或者你甚至可以把回調的工作到一個隊列。再次,你可以做10個阻塞獲取隊列,每次執行結果。
如果每個線程都可以返回多個對象,他們可以把警戒值或回調到時,他們正在做的,你的主線程不斷出現,直到它顯示的是10個哨兵隊列。
爲什麼你的問題是一個問題?一個已經完成但尚未加入的線程正在浪費很少的資源(基本上,內核或用戶空間中操作系統維護的表中的一個小表項)。 – abarnert 2012-07-20 00:25:06
我想這不完全是一個問題,但它似乎是一個非常不雅的解決方案,如果空閒線程不是一個只是等待加入的問題,我想我不會擔心它。 – hkothari 2012-07-20 00:39:37
備註:如果您的「評估」操作受CPU限制,那麼在此應用程序中使用線程可能沒有獲得太多好處。閱讀CPython的全球解釋器鎖定(GIL)。 – 2012-07-20 01:00:09