2010-01-26 23 views
8

Configuré un proceso que leía una cola para que las URL entrantes se descargaran, pero cuando urllib2 abre una conexión, el sistema se cuelga.Proceso de Python bloqueado por 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() 

De otro módulo puedo agregar URL y cuando quiero puedo detener el proceso y esperar el proceso de cierre.

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() 

El problema es que cuando uso urlopen ("respuesta = urllib2.urlopen (petición)") que sigue siendo todo bloqueado.

No hay problema si llamo a la función de descarga() o si utilizo solo hilos sin proceso.

Respuesta

4

El problema aquí no es urllib2, sino el uso del módulo de multiprocesamiento. Al utilizar el módulo de multiprocesamiento en Windows, no debe usar código que se ejecute inmediatamente al importar su módulo; en su lugar, coloque elementos en el módulo principal dentro de un bloque if __name__=='__main__'. Consulte la sección "Importación segura del módulo principal" here.

Para su código, hacer este cambio siguiente en el módulo de descarga:

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

Y en el módulo principal:

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

Debido a que no hace esto, cada vez que el subproceso se comenzó ejecutaría el código principal nuevamente y comenzaría otro proceso, causando el bloqueo.

+0

No uso Windows pero su sugerencia de utilizar una función start() soluciona el problema. ¡Gracias! – Davmuz

Cuestiones relacionadas