2013-06-12 72 views
0

我目前正在用Threading/workpool測試一些東西;我創建了400個線程,總共下載了5000個URLS ......問題是400個線程中的一些線程「凍結」,當查看我的進程時,我發現每個運行凍結時有15個線程,最終一段時間後關閉1由1.Python線程沒有完成

我的問題是如果有一種'計時器'/'計數器'殺死一個線程,如果它沒有完成後x秒的方式。

# download2.py - Download many URLs using multiple threads. 
import os 
import urllib2 
import workerpool 
import datetime 
from threading import Timer 

class DownloadJob(workerpool.Job): 
    "Job for downloading a given URL." 
    def __init__(self, url): 
     self.url = url # The url we'll need to download when the job runs 
    def run(self): 
     try: 
      url = urllib2.urlopen(self.url).read() 
     except: 
      pass 

# Initialize a pool, 400 threads in this case 
pool = workerpool.WorkerPool(size=400) 

# Loop over urls.txt and create a job to download the URL on each line 
print datetime.datetime.now() 
for url in open("urls.txt"): 
    job = DownloadJob(url.strip()) 
    pool.put(job) 

# Send shutdown jobs to all threads, and wait until all the jobs have been completed 
pool.shutdown() 
pool.wait() 
print datetime.datetime.now() 
+4

你有沒有進行一些分析,看是否400個線程確實提高你的表現?線程不是免費的;每個線程都有一定的開銷,理想的線程數量可能遠遠少於此。 –

回答

0

urlopen接受超時值,這將是處理它的最好方法,我認爲。

但我與400個線程可能是太多的

+0

我試圖看看用5,100,200和400線程處理這5000個URL的時間。 + - 200是最快的。 – Coryza

1

The problem is that some of the 400 threads are "freezing"...

這是因爲這條線的最有可能的評議同意...

url = urllib2.urlopen(self.url).read() 

默認情況下,Python會永遠等待一個遠程服務器來響應,所以如果你的一個URL指向一個忽略SYN數據包的服務器,或者其他的只是真的慢,那麼該線程可能永遠被阻塞。

可以使用timeout參數的urlopen()設置限制爲線程將等待遠程主機迴應...

url = urllib2.urlopen(self.url, timeout=5).read() # Time out after 5 seconds 

...或者你可以用全局設置它,而不是socket.setdefaulttimeout()通過把這些線在你的代碼的頂部...

import socket 
socket.setdefaulttimeout(5) # Time out after 5 seconds 
+0

它工作完美!非常感謝。但是,當我這樣做時,URL永遠不會被下載,我應該添加什麼代碼,以便URL再次嘗試(如果可能,請使用短代碼)?) – Coryza

+0

@Coryza這有點複雜,因爲多線程性質的代碼。一個簡單的黑客就是擁有一個全局列表,並將url附加到'except'塊的列表中(因爲列表附加是線程安全的)。一旦'pool.wait()'返回,您可以重複失敗的列表,或者將其轉儲到一個文件中,同時記住這些URL可能在將來永遠不可用。 – Aya

+0

已經害怕那個..嗯... – Coryza