urllib2与多进程无用?
我最近尝试加速一个小工具,这个工具使用urllib2发送请求到一个(非官方的)Twitter按钮计数网址(超过2000个网址),然后解析它的结果。我在这里阅读了关于多线程和多进程的讨论,发现多线程反而让整个过程变慢,相比于标准的非线程版本。但我找不到一个(可能非常简单的)问题的答案:
使用多进程能加速网址请求吗,还是说瓶颈在于网络适配器?我不太明白,比如说urllib2的open方法中,哪一部分可以并行处理,以及该怎么做...
补充:这是我想要加速的请求和当前的多进程设置:
urls=["www.foo.bar", "www.bar.foo",...]
tw_url='http://urls.api.twitter.com/1/urls/count.json?url=%s'
def getTweets(self,urls):
for i in urls:
try:
self.tw_que=urllib2.urlopen(tw_url %(i))
self.jsons=json.loads(self.tw_que.read())
self.tweets.append({'url':i,'date':today,'tweets':self.jsons['count']})
except ValueError:
print ....
continue
return self.tweets
if __name__ == '__main__':
pool = multiprocessing.Pool(processes=4)
result = [pool.apply_async(getTweets(i,)) for i in urls]
[i.get() for i in result]
5 个回答
7
又来了,关于GIL(全局解释器锁)的讨论。事情是这样的,使用urllib2获取内容主要是依赖输入输出(IO)的操作。对于这种IO密集型的任务,使用原生线程和多进程的性能是差不多的(线程的问题主要出现在CPU密集型的任务上)。没错,你可以加速这个过程,我自己就用Python的线程和大约10个下载线程做过。
基本上,你可以用一个生产者-消费者的模型,一个线程(或进程)负责生成要下载的URL,然后有
这里有一些伪代码:
# Make sure that the queue is thread-safe!!
def producer(self):
# Only need one producer, although you could have multiple
with fh = open('urllist.txt', 'r'):
for line in fh:
self.queue.enqueue(line.strip())
def consumer(self):
# Fire up N of these babies for some speed
while True:
url = self.queue.dequeue()
dh = urllib2.urlopen(url)
with fh = open('/dev/null', 'w'): # gotta put it somewhere
fh.write(dh.read())
如果你下载的数据量非常大(比如几百MB),而且单个请求已经把带宽用满了,那么同时进行多个下载就没什么意义了。通常情况下,进行多个下载的原因是请求的数据量小,而且延迟和开销相对较高。
7
看看这个叫做 gevent 的东西,特别是这个例子: concurrent_download.py。它的速度会比多进程和多线程快很多,而且还能轻松处理成千上万的连接。