8

ダウンロードする着信 URL のキューを読み取るプロセスをセットアップしましたが、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 ("response = urllib2.urlopen(request)") を使用すると、すべてブロックされたままになることです。

download() 関数を呼び出したり、Process を使用せずにスレッドのみを使用したりする場合は問題ありません。

4

1 に答える 1

4

ここでの問題は urllib2 ではなく、マルチプロセッシング モジュールの使用です。Windows でマルチプロセッシング モジュールを使用する場合、モジュールをインポートしたときにすぐに実行されるコードを使用してはなりません。代わりに、メイン モジュール内のものをif __name__=='__main__'ブロック内に配置してください。こちらのセクション「メインモジュールの安全なインポート」を参照してください

コードについては、ダウンローダ モジュールで次の変更を行います。

#....
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')
    #....

これを行わなかったため、サブプロセスが開始されるたびに、メイン コードが再度実行され、別のプロセスが開始され、ハングが発生しました。

于 2010-01-26T12:22:50.197 に答える