我设置了一个进程来读取要下载的传入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()
从另一个模块我可以添加网址,当我想要时,我可以停止进程并等待进程关闭。
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的线程,则没有问题。
答案 0 :(得分: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')
#....
因为你没有这样做,所以每次启动子进程时,它都会再次运行主代码并启动另一个进程,导致挂起。