因为我的scaper运行很慢(一次一个页面),所以我试着使用线程来让它工作得更快。我有一个抓取(网站)函数,它接受一个要抓取的网站,所以我可以很容易地创建每个线程并在每个线程上调用start()。
现在,我想实现一个num_threads变量,它是我希望同时运行的线程数。处理这些多线程的最佳方式是什么?
例如:假设num_threads =5,我的目标是启动5个线程,然后抓取列表中的前5个网站并抓取它们,然后如果线程#3完成,它将立即抓取列表中的第6个网站抓取,而不是等到其他线程结束。
有什么关于如何处理它的建议吗?谢谢
发布于 2015-02-03 20:46:20
那得看情况。
如果您的代码大部分时间都在等待网络操作(很可能是在web抓取应用程序中),那么线程是合适的。实现线程池的最好方法是在3.4中使用concurrent.futures
。如果做不到这一点,您可以创建一个threading.Queue
对象并将每个线程编写为一个无限循环,该循环使用队列中的工作对象并对其进行处理。
如果您的代码在下载数据后大部分时间都在处理数据,那么由于GIL的存在,线程是无用的。concurrent.futures
提供了对进程并发的支持,但同样只能在3.4+中工作。对于较老的Python,请使用multiprocessing
。它提供了一种Pool
类型,可以简化创建进程池的过程。
您应该分析您的代码(使用cProfile
),以确定您正在经历这两种情况中的哪一种。
发布于 2015-02-03 20:48:09
如果您使用的是Python3,请查看concurrent.futures.ThreadPoolExecutor
从文档ThreadPoolExecutor Example中提取的示例
import concurrent.futures
import urllib.request
URLS = ['http://www.foxnews.com/',
'http://www.cnn.com/',
'http://europe.wsj.com/',
'http://www.bbc.co.uk/',
'http://some-made-up-domain.com/']
# Retrieve a single page and report the url and contents
def load_url(url, timeout):
conn = urllib.request.urlopen(url, timeout=timeout)
return conn.readall()
# We can use a with statement to ensure threads are cleaned up promptly
with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
# Start the load operations and mark each future with its URL
future_to_url = {executor.submit(load_url, url, 60): url for url in URLS}
for future in concurrent.futures.as_completed(future_to_url):
url = future_to_url[future]
try:
data = future.result()
except Exception as exc:
print('%r generated an exception: %s' % (url, exc))
else:
print('%r page is %d bytes' % (url, len(data)))
如果你使用的是Python 2,有一个可用的后端口:
from concurrent import futures
import urllib.request
URLS = ['http://www.foxnews.com/',
'http://www.cnn.com/',
'http://europe.wsj.com/',
'http://www.bbc.co.uk/',
'http://some-made-up-domain.com/']
def load_url(url, timeout):
return urllib.request.urlopen(url, timeout=timeout).read()
with futures.ThreadPoolExecutor(max_workers=5) as executor:
future_to_url = dict((executor.submit(load_url, url, 60), url)
for url in URLS)
for future in futures.as_completed(future_to_url):
url = future_to_url[future]
if future.exception() is not None:
print('%r generated an exception: %s' % (url,
future.exception()))
else:
print('%r page is %d bytes' % (url, len(future.result())))
https://stackoverflow.com/questions/28308285
复制相似问题