簡體   English   中英

python,如何增量創建Threads

[英]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 的大量開銷。

線程化這些查詢可以加快您的進程,但會產生另一組問題,例如數據庫過載和允許的最大會話數。

第一種方法:將許多項目 ID 加載到每個查詢中

相反,請嘗試改進您的查詢。 您能否編寫一個查詢來發送一長串產品並返回匹配項? 也許是這樣的:

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 密集型任務。

http://www.gevent.org/intro.html#example

暫無
暫無

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

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