2010-01-26 5 views
8

Я установил процесс, который читал очередь для входящих URL-адресов для загрузки, но когда urllib2 открыл соединение, зависание системы.Python Process заблокирован 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() 

Из другого модуля я могу добавить URL-адреса, и когда захочу, я могу остановить процесс и ждать завершения процесса.

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

Проблема заключается в том, что, когда я использую urlopen ("ответ = urllib2.urlopen (запрос)") он остается все заблокированные.

Нет проблем, если я вызываю функцию download() или когда я использую только потоки без процесса.

ответ

4

Проблема здесь не в urllib2, а в использовании многопроцессорного модуля. При использовании модуля многопроцессорности под Windows вы не должны использовать код, который запускается сразу при импорте вашего модуля, вместо этого помещайте вещи в основной модуль внутри блока if __name__=='__main__'. См. Раздел «Безопасный импорт основного модуля» here.

Для вашего кода, сделать это изменение следующий в модуле загрузчика:

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

И в главном модуле:

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

Потому что вы не сделали этого, каждый раз, когда подпроцесс было он снова запускает основной код и запускает другой процесс, вызывая зависание.

+0

Я не использую Windows, но ваше предложение использовать функцию start() исправить проблему. Благодаря! – Davmuz