2010-01-26 21 views
8

Ho impostato un processo che legge una coda per gli url in arrivo da scaricare ma quando urllib2 apre una connessione il sistema si blocca.Processo Python bloccato da urllib2

import urllib2, multiprocessing 
from threading import Thread 
from Queue import Queue 
from multiprocessing import Queue as ProcessQueue, Process 

def download(url): 
    """Download a page from an url. 
    url [str]: url to get. 
    return [unicode]: page downloaded. 
    """ 
    if settings.DEBUG: 
     print u'Downloading %s' % url 
    request = urllib2.Request(url) 
    response = urllib2.urlopen(request) 
    encoding = response.headers['content-type'].split('charset=')[-1] 
    content = unicode(response.read(), encoding) 
    return content 

def downloader(url_queue, page_queue): 
    def _downloader(url_queue, page_queue): 
     while True: 
      try: 
       url = url_queue.get() 
       page_queue.put_nowait({'url': url, 'page': download(url)}) 
      except Exception, err: 
       print u'Error downloading %s' % url 
       raise err 
      finally: 
       url_queue.task_done() 

    ## Init internal workers 
    internal_url_queue = Queue() 
    internal_page_queue = Queue() 
    for num in range(multiprocessing.cpu_count()): 
     worker = Thread(target=_downloader, args=(internal_url_queue, internal_page_queue)) 
     worker.setDaemon(True) 
     worker.start() 

    # Loop waiting closing 
    for url in iter(url_queue.get, 'STOP'): 
     internal_url_queue.put(url) 

    # Wait for closing 
    internal_url_queue.join() 

# Init the queues 
url_queue = ProcessQueue() 
page_queue = ProcessQueue() 

# Init the process 
download_worker = Process(target=downloader, args=(url_queue, page_queue)) 
download_worker.start() 

Da un altro modulo posso aggiungere URL e quando voglio posso interrompere il processo e attendere la chiusura del processo.

import module 

module.url_queue.put('http://foobar1') 
module.url_queue.put('http://foobar2') 
module.url_queue.put('http://foobar3') 
module.url_queue.put('STOP') 
downloader.download_worker.join() 

Il problema è che quando uso urlopen ("risposta = urllib2.urlopen (richiesta)") che rimanga bloccato tutto.

Non ci sono problemi se chiamo la funzione download() o quando utilizzo solo thread senza Process.

risposta

4

Il problema qui non è urllib2, ma l'uso del modulo multiprocessing. Quando si utilizza il modulo multiprocessing sotto Windows, non è necessario utilizzare il codice che viene eseguito immediatamente durante l'importazione del modulo, ma inserire le cose nel modulo principale all'interno di un blocco if __name__=='__main__'. Vedere la sezione "Importazione sicura del modulo principale" here.

Per il vostro codice, fare questo cambiamento in seguito nel modulo downloader:

#.... 
def start(): 
    global download_worker 
    download_worker = Process(target=downloader, args=(url_queue, page_queue)) 
    download_worker.start() 

E nel modulo principale:

import module 
if __name__=='__main__': 
    module.start() 
    module.url_queue.put('http://foobar1') 
    #.... 

Perché non hai fatto questo, ogni volta che il sottoprocesso era avviato avrebbe eseguito nuovamente il codice principale e avviare un altro processo, causando il blocco.

+0

Non utilizzo Windows ma il tuo suggerimento di utilizzare una funzione start() risolve il problema. Grazie! – Davmuz