[英]python, how to incrementally create Threads
我有一個大約 60,000 個項目的列表——我想向數據庫發送查詢以檢查它們是否存在以及它們是否返回一些計算結果。 我運行一個普通查詢,同時逐一遍歷列表,查詢已經運行了最后 4 天。 我想我可以使用線程模塊來改進這一點。 我做了這樣的事情
if __name__ == '__main__':
for ra, dec in candidates:
t = threading.Thread(target=search_sl, args=(ra,dec, q))
t.start()
t.join()
我只測試了 10 個項目並且工作正常 - 當我提交整個 60k 項目列表時,我遇到了錯誤,即“超出最大會話數”。 我想做的是一次創建 10 個線程。 當第一束線程完成執行時,我發送另一個請求,依此類推。
您可以嘗試使用多處理模塊中提供的進程池。 這是 python 文檔中的示例:
from multiprocessing import Pool
def f(x):
return x*x
if __name__ == '__main__':
pool = Pool(processes=4) # start 4 worker processes
result = pool.apply_async(f, [10]) # evaluate "f(10)" asynchronously
print result.get(timeout=1) # prints "100" unless your computer is *very* slow
print pool.map(f, range(10)) # prints "[0, 1, 4,..., 81]"
http://docs.python.org/library/multiprocessing.html#using-a-pool-of-workers
嘗試增加進程數,直到達到系統可以支持的最大值。
您的問題是在一個數據庫上有 60,000 個不同的查詢。 對每個項目進行單個查詢意味着打開連接和調用 DB cursor session 的大量開銷。
線程化這些查詢可以加快您的進程,但會產生另一組問題,例如數據庫過載和允許的最大會話數。
相反,請嘗試改進您的查詢。 您能否編寫一個查詢來發送一長串產品並返回匹配項? 也許是這樣的:
SELECT item_id, *
FROM items
WHERE item_id IN (id1, id2, id3, id4, id5, ....)
Python 為這種 if 查詢提供了方便的接口,以便IN
子句可以使用 pythonic 列表。 通過這種方式,您可以將長長的項目列表分解為 60 個查詢,每個查詢有 1,000 個 ID。
另一種有趣的方法是使用您的項目 ID 在數據庫中創建一個臨時表。 只要連接存在,臨時表就會持續存在,因此您不必擔心清理問題。 也許是這樣的:
CREATE TEMPORARY TABLE
item_ids_list (id INT PRIMARY KEY); # Remember indexing!
使用適當的 Python 庫插入 ID:
INSERT INTO item_ids_list ... # Insert your 60,000 items here
得到你的結果:
SELECT * FROM items WHERE items.id IN (SELECT * FROM items_ids_list);
首先,您只加入最后一個線程。 不能保證它會在最后完成。 你應該這樣使用:
from time import sleep
delay = 0.5
tlist = [threading.Thread(target=search_sl, args=(ra,dec, q)) for ra, dec in candidates ]
map(lambda t:t.start(), tlist)
while(any(map(lambda t:t.isAlive()))): sleep(delay)
第二個問題是目前運行的 60K 線程需要非常巨大的硬件資源:-) 最好將任務排隊,然后由工作人員處理。 必須限制工作線程的數量。 就像那樣(還沒有測試代碼,但我希望這個想法很清楚):
from Queue import Queue
from threading import Thread
from time import sleep
tasks = Queue()
map(tasks.put, candidates)
maxthreads = 50
delay = 0.1
try:
threads = [Thread(target=search_sl, args=tasks.get()) \
for i in xrange(0,maxthreads) ]
except Queue.Empty:
pass
map(lambda t:t.start(), threads)
while not tasks.empty():
threads = filter(lambda t:t.isAlive(), threads)
while len(threads) < maxthreads:
try:
t = Thread(target=search_sl, args=tasks.get())
t.start()
threads.append(t)
except Queue.Empty:
break
sleep(delay)
while(any(map(lambda t:t.isAlive(), threads))): sleep(delay)
由於它是一個 IO 任務,線程或進程都不適合它。 如果您需要並行化計算任務,則可以使用它們。 所以,請現代一點™,使用類似gevent
的東西來並行執行 IO 密集型任務。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.